Commit 25cb4f8de732ca0ad1613c21a026e140a561fe64

Authored by Myriam Bouchemit
2 parents b87da101 864d0212

Merge branch 'master' of https://gitlab.irap.omp.eu/CDPP/AMDA_IHM

help/plotHOWTO
1 1 <li>1. To plot a parameter <i>drag</i> it from the Parameters tree and <i>drop</i> onto the panel
2   -<li>2. <i>Link to MultiPlot</i> replaces the individual plot tab TimeSelector with the common for all plot tabs "MultiTime" Selector
3   -<li>3. Check <i>Extended Plot Options</i> to get control over all available plot options
  2 +<li>2. Check <i>Extended Plot Options</i> to get control over all available plot options
  3 +
4 4  
5   -
6 5 \ No newline at end of file
... ...
js/app/controllers/InteractiveModule.js
... ... @@ -37,12 +37,15 @@ Ext.define(&#39;amdaDesktop.InteractiveModule&#39;, {
37 37 /**
38 38 * Window Creation method of the Module
39 39 */
40   - createWindow : function (onShowEvent) {
  40 + createWindow : function (onShowEvent, onAfterCreateObject) {
41 41  
42 42 if (this.linkedNode === null){
43 43 this.createLinkedNode();
44 44 }
45   - this.createObject();
  45 + this.createObject();
  46 + if (onAfterCreateObject) {
  47 + onAfterCreateObject();
  48 + }
46 49 var desktop = this.app.getDesktop();
47 50 var win = desktop.getWindow(this.id);
48 51 var me = this;
... ...
js/app/controllers/PlotModule.js
... ... @@ -13,8 +13,8 @@ Ext.define(&#39;amdaDesktop.PlotModule&#39;, {
13 13  
14 14 requires: [
15 15 'amdaUI.PlotUI',
16   - 'amdaPlotObj.PlotRequestObject',
17   - 'amdaModel.PlotNode',
  16 + 'amdaPlotObj.MultiplotRequestObject',
  17 + 'amdaModel.MultiplotNode',
18 18 'amdaUI.PlotTabResultUI',
19 19 'amdaPlotComp.PlotPreviewUI'
20 20 ],
... ... @@ -26,7 +26,7 @@ Ext.define(&#39;amdaDesktop.PlotModule&#39;, {
26 26 * @cfg {String} data models
27 27 * @required
28 28 */
29   - nodeDataModel : 'amdaModel.PlotNode',
  29 + nodeDataModel : 'amdaModel.MultiplotNode',
30 30  
31 31 /**
32 32 * @cfg {String} window definitions
... ... @@ -40,173 +40,197 @@ Ext.define(&#39;amdaDesktop.PlotModule&#39;, {
40 40  
41 41 plotResultWindowsManager : new Ext.AbstractManager(),
42 42  
43   - computeResultWindowSize : function(panelResult)
44   - {
45   - var size = panelResult.getImageSize();
46   - size.width += 30;
47   - size.height += 95;
48   -
49   - return size;
50   - },
  43 + computeResultWindowSize : function(panelResult) {
  44 + var size = panelResult.getImageSize();
  45 + size.width += 30;
  46 + size.height += 95;
  47 + return size;
  48 + },
51 49  
52   - computePreviewWindowSize : function(previewContent)
53   - {
54   - var size = previewContent.getImageSize();
55   - size.width += 30;
56   - size.height += 65;
57   -
58   - return size;
59   - },
  50 + computePreviewWindowSize : function(previewContent) {
  51 + var size = previewContent.getImageSize();
  52 + size.width += 30;
  53 + size.height += 65;
  54 + return size;
  55 + },
60 56  
61 57 updateInteractiveSession : function(session, newplot) {
62   - var me = this;
63   -
64   -
65   -
66   - Ext.each(session.result, function (tabResult, index) {
67   - if (logExecTime && tabResult.exectime)
68   - {
69   - console.log("CMD EXEC TIME FOR "+tabResult.plot+" = "+tabResult.exectime+"ms");
70   - }
  58 + var me = this;
71 59  
72   - if (tabResult.preview)
73   - {
74   - var plotPreviewConfig = {
75   - folder : session.folder,
76   - plotFile : tabResult.plot,
77   - context : tabResult.context,
78   - tabId : tabResult.id
79   - };
80   - me.updatePreview(plotPreviewConfig);
81   - return;
82   - }
83   -
84   - var winResultId = tabResult.id+"-win";
85   -
86   - var winResult = me.getWindowResult(winResultId);
87   -
88   - var plotTabConfig = {
89   - folder : session.folder,
90   - plotFile : tabResult.plot,
91   - context : tabResult.context,
92   - tabId : tabResult.id,
93   - multiplot : tabResult.multiplot,
94   - isInterval: tabResult.isInterval,
95   - ttName : tabResult.ttName,
96   - ttIndex : tabResult.ttIndex,
97   - ttNbIntervals : tabResult.ttNbIntervals,
98   - ttFileIndex : tabResult.ttFileIndex
99   - };
  60 +
  61 + Ext.each(session.result, function (tabResult, index) {
  62 + if (logExecTime && tabResult.exectime) {
  63 + console.log("CMD EXEC TIME FOR "+tabResult.plot+" = "+tabResult.exectime+"ms");
  64 + }
  65 +
  66 + if (tabResult.preview) {
  67 + var plotPreviewConfig = {
  68 + folder : session.folder,
  69 + plotFile : tabResult.plot,
  70 + context : tabResult.context,
  71 + interactiveId : tabResult.id
  72 + };
  73 + me.updatePreview(plotPreviewConfig);
  74 + return;
  75 + }
  76 +
  77 + var winResultId = tabResult.id+"-win";
100 78  
101   - if (winResult == null) {
102   -
103   - var x = 50 + tabResult.index * 50;
104   - var y = 100 + tabResult.index * 20;
105   -
106   - //create new result win
107   - var panelResult = new amdaUI.PlotTabResultUI(plotTabConfig);
  79 + var winResult = me.getWindowResult(winResultId);
108 80  
109   - var size = me.computeResultWindowSize(panelResult);
  81 + var plotTabConfig = {
  82 + folder : session.folder,
  83 + plotFile : tabResult.plot,
  84 + context : tabResult.context,
  85 + interactiveId : tabResult.id,
  86 + isInterval: tabResult.isInterval,
  87 + ttName : tabResult.ttName,
  88 + ttIndex : tabResult.ttIndex,
  89 + ttNbIntervals : tabResult.ttNbIntervals,
  90 + ttFileIndex : tabResult.ttFileIndex
  91 + };
110 92  
111   - var win = myDesktopApp.getDesktop().createWindow({
112   - id : tabResult.id+"-win",
113   - title : 'Plot '+(tabResult.index+1),
114   - width : size.width,
115   - height: size.height,
116   - x : x,
117   - y : y,
118   - layout: 'fit',
119   - items : [
120   - panelResult
121   - ],
122   - listeners: {
123   - scope: me,
124   - beforeclose: function(win,opt) {
125   - me.plotResultWindowsManager.unregister(win);
126   - }
127   - },
128   - getPanelResult: function() {
129   - return panelResult;
130   - }
131   - });
132   - win.show();
133   - me.plotResultWindowsManager.register(win);
134   - }
135   - else
136   - {
137   - //update result
138   - winResult.getPanelResult().updatePlotImage(plotTabConfig, newplot);
139   - //update window size
140   - var size = me.computeResultWindowSize(winResult.getPanelResult());
141   - winResult.setSize(size.width, size.height);
142   -
143   - winResult.toFront();
144   - }
145   - });
  93 + if (winResult == null) {
  94 + var x = 50 + tabResult.index * 50;
  95 + var y = 100 + tabResult.index * 20;
  96 + //create new result win
  97 + var panelResult = new amdaUI.PlotTabResultUI(plotTabConfig);
  98 +
  99 + var size = me.computeResultWindowSize(panelResult);
  100 +
  101 + var win = myDesktopApp.getDesktop().createWindow({
  102 + id : tabResult.id+"-win",
  103 + title : tabResult.title,
  104 + width : size.width,
  105 + height: size.height,
  106 + x : x,
  107 + y : y,
  108 + layout: 'fit',
  109 + items : [
  110 + panelResult
  111 + ],
  112 + listeners: {
  113 + scope: me,
  114 + beforeclose: function(win,opt) {
  115 + me.plotResultWindowsManager.unregister(win);
  116 + }
  117 + },
  118 + getPanelResult: function() {
  119 + return panelResult;
  120 + }
  121 + });
  122 + win.show();
  123 + me.plotResultWindowsManager.register(win);
  124 + }
  125 + else {
  126 + //update result
  127 + winResult.getPanelResult().updatePlotImage(plotTabConfig, newplot);
  128 + //update window size
  129 + var size = me.computeResultWindowSize(winResult.getPanelResult());
  130 + winResult.setTitle(tabResult.title);
  131 + winResult.setSize(size.width, size.height);
  132 + winResult.toFront();
  133 + }
  134 + });
146 135 },
147 136  
148 137 closeInteractiveSession : function() {
149   - var me = this;
150   - this.plotResultWindowsManager.each(function (key, value, length) {
151   - value.close();
152   - });
  138 + var me = this;
  139 + this.plotResultWindowsManager.each(function (key, value, length) {
  140 + value.close();
  141 + });
153 142 },
154   -
  143 +
155 144 updatePreview : function(plotPreviewConfig) {
156   - var winPreviewId = "plot-preview-win";
157   -
158   - var winPreview = this.getWindowResult(winPreviewId);
159   -
160   - if (winPreview == null) {
161   - //create new preview win
162   - var previewContent = new amdaPlotComp.PlotPreviewUI(plotPreviewConfig);
163   -
164   - var size = this.computePreviewWindowSize(previewContent);
165   -
166   - var win = myDesktopApp.getDesktop().createWindow({
167   - id : winPreviewId,
168   - title : 'Plot Preview',
169   - width : size.width,
170   - height: size.height,
171   - layout: 'fit',
172   - items : [
173   - previewContent
174   - ],
175   - listeners: {
176   - scope: this,
177   - beforeclose: function(win,opt) {
178   - this.plotResultWindowsManager.unregister(win);
179   - }
180   - },
181   - getPreviewContent: function() {
182   - return previewContent;
183   - }
184   - });
185   - win.show();
186   - this.plotResultWindowsManager.register(win);
187   - }
188   - else
189   - {
190   - //update result
191   - winPreview.getPreviewContent().updatePlotImage(plotPreviewConfig);
192   - //update window size
193   - var size = this.computePreviewWindowSize(winPreview.getPreviewContent());
194   - winPreview.setSize(size.width, size.height);
195   - winPreview.toFront();
196   - }
197   - },
198   -
199   - getInteractiveMultiPlotState : function() {
200   - var state = {};
201   - this.plotResultWindowsManager.each(function (key, value, length) {
202   - if (value.getPanelResult)
203   - state[value.getPanelResult().tabId] = value.getPanelResult().getInteractiveMultiPlotState();
204   - });
205   - return state;
  145 + var winPreviewId = "plot-preview-win";
  146 +
  147 + var winPreview = this.getWindowResult(winPreviewId);
  148 +
  149 + if (winPreview == null) {
  150 + //create new preview win
  151 + var previewContent = new amdaPlotComp.PlotPreviewUI(plotPreviewConfig);
  152 +
  153 + var size = this.computePreviewWindowSize(previewContent);
  154 +
  155 + var win = myDesktopApp.getDesktop().createWindow({
  156 + id : winPreviewId,
  157 + title : 'Plot Preview',
  158 + width : size.width,
  159 + height: size.height,
  160 + layout: 'fit',
  161 + items : [
  162 + previewContent
  163 + ],
  164 + listeners: {
  165 + scope: this,
  166 + beforeclose: function(win,opt) {
  167 + this.plotResultWindowsManager.unregister(win);
  168 + }
  169 + },
  170 + getPreviewContent: function() {
  171 + return previewContent;
  172 + }
  173 + });
  174 + win.show();
  175 + this.plotResultWindowsManager.register(win);
  176 + }
  177 + else {
  178 + //update result
  179 + winPreview.getPreviewContent().updatePlotImage(plotPreviewConfig);
  180 + //update window size
  181 + var size = this.computePreviewWindowSize(winPreview.getPreviewContent());
  182 + winPreview.setSize(size.width, size.height);
  183 + winPreview.toFront();
  184 + }
206 185 },
207 186  
208 187 getWindowResult: function(winResultId){
209 188 if (!this.plotResultWindowsManager.get(winResultId)) return null;
210 189 return this.plotResultWindowsManager.get(winResultId);
  190 + },
  191 +
  192 + addParameter : function(paramNode) {
  193 + var me = this;
  194 + var desktop = this.app.getDesktop();
  195 + var win = desktop.getWindow(this.id);
  196 + if (win) {
  197 + me.getUiContent().addParameter(paramNode, false);
  198 + win.show();
  199 + }
  200 + else {
  201 + this.createWindow(function () {
  202 + me.getUiContent().addParameter(paramNode, true);
  203 + });
  204 + }
  205 + },
  206 +
  207 + editPlot : function(plotNode) {
  208 + var me = this;
  209 + var desktop = this.app.getDesktop();
  210 + var win = desktop.getWindow(this.id);
  211 + if (win) {
  212 + // Plot UI is opened => add plot in a new tab
  213 + me.getUiContent().editPlot(plotNode);
  214 + win.show();
  215 + }
  216 + else {
  217 + // Plot UI is closed
  218 + this.createWindow(null, function() {
  219 + //This is the onAfterCreateObject callback
  220 + //Add plot node to the multiplot object
  221 + me.linkedNode.get('object').plots().removeAll();
  222 + me.linkedNode.get('object').plots().add(plotNode);
  223 + });
  224 + }
  225 + },
  226 +
  227 + syncAfterRename: function(renamedNode) {
  228 + var me = this;
  229 + var desktop = this.app.getDesktop();
  230 + var win = desktop.getWindow(this.id);
  231 + if (win) {
  232 + me.getUiContent().updateTabs();
  233 + me.getUiContent().updateRequestName(renamedNode);
  234 + }
211 235 }
212 236 });
... ...
js/app/models/AmdaNode.js
... ... @@ -128,20 +128,7 @@ Ext.define(&#39;amdaModel.AmdaNode&#39;, {
128 128 }
129 129 // if this node is a leaf and have no child
130 130 else if (this.isLeaf() || this.get('nodeType' ) == 'derivedParam' ) {
131   - if (this.get('nodeType') == 'plottab') {
132   - itemKind = amdaUI.ExplorerUI.ITEM_KIND_PTAB;
133   - }
134   - else {
135   - itemKind = amdaUI.ExplorerUI.ITEM_KIND_LEAF;
136   - }
137   - }
138   - else if (this.get('nodeType') == 'request') {
139   - if (this.get('tabs') && (this.get('tabs').length > 0)) {
140   - itemKind = amdaUI.ExplorerUI.ITEM_KIND_LEAF;
141   - }
142   - else {
143   - itemKind = amdaUI.ExplorerUI.ITEM_KIND_DIRE;
144   - }
  131 + itemKind = amdaUI.ExplorerUI.ITEM_KIND_LEAF;
145 132 }
146 133 else if (this.get('isParameter') && this.get('nodeType' ) != 'derivedParam' ) {
147 134 itemKind = amdaUI.ExplorerUI.ITEM_KIND_PARA;
... ...
js/app/models/AmdaTimeObject.js
... ... @@ -7,11 +7,7 @@
7 7 *
8 8 * @author elena
9 9 * @version $Id: AmdaTimeObject.js 1534 2013-05-24 13:30:26Z myriam $
10   - * @todo Validations
11   - ******************************************************************************
12   - * FT Id : Date : Name - Description
13   - ******************************************************************************
14   - * : :07/07/2011: elena โ€“ creation
  10 + * @todo Validations
15 11 */
16 12  
17 13  
... ... @@ -26,66 +22,70 @@ Ext.define(&#39;amdaModel.TTobject&#39;, {
26 22 }
27 23 });
28 24  
29   -
30 25 Ext.define('amdaModel.AmdaTimeObject', {
31 26 extend: 'amdaModel.AmdaObject',
32 27 statics:{
33 28 inputTimeSrc: ['TimeTable','Interval','Catalog']
34   - },
  29 + },
35 30 fields : [
36   - { name: 'resultId', type: 'string'},
37   - { name: 'folderId', type: 'string'},
38   - { name: 'processId', type: 'string'},
39   - { name: 'timesrc', type: 'string'/*, defaultValue: amdaModel.AmdaTimeObject.inputTimeSrc[1] /*'Interval'*/ },
40   - { name: 'startDate', type: 'date', defaultValue:Ext.Date.add(Ext.Date.clearTime(new Date()),Ext.Date.DAY,-1),
41   - convert: function(value,rec) {
42   - if (!Ext.isDate(value)) {
43   - var valueString = new String(value);
44   - var date = new Date(valueString.replace(/\-/g,'\/').replace(/[T|Z]/g,' '));
45   - return date;
46   - }
47   - return value;
48   - }
49   - },
50   - { name: 'stopDate', type: 'date', defaultValue: Ext.Date.clearTime (new Date()), persist: false,
51   - convert: function(value,rec) {
52   - if (!Ext.isDate(value)){
53   - var valueString = new String(value);
54   - var date = new Date(valueString.replace(/\-/g,'\/').replace(/[T|Z]/g,' '));
55   - return date;
56   - }
57   - return value;
58   - }
59   -
60   - },
61   - {
62   - name: 'durationDay', type: 'int',
63   - convert: function(value, rec) {
64   - return Ext.String.leftPad(Math.floor((rec.get('stopDate') - rec.get('startDate'))/86400000),4,'0');
65   - }
66   - },
67   - {
68   - name: 'durationHour', type: 'int',
69   - convert: function(value, rec) {
70   - var diffH = (rec.get('stopDate') - rec.get('startDate'))/3600000 % 24;
71   - return Ext.String.leftPad(Math.floor(diffH), 2, '0');
72   - }
73   - },
74   - {
75   - name: 'durationMin', type: 'int',
76   - convert: function(value, rec) {
77   - var diffM = (rec.get('stopDate') - rec.get('startDate'))/60000 % 60;
78   - return Ext.String.leftPad(Math.floor(diffM), 2, '0');
79   - }
80   - },
81   - {
82   - name: 'durationSec', type: 'int',
83   - convert: function(value, rec) {
84   - var diffS = (rec.get('stopDate') - rec.get('startDate'))/1000 % 60;
85   - return Ext.String.leftPad(Math.floor(diffS), 2, '0');
86   - }
87   - },
88   - { name: 'timeTables', defaultValue: null } // array of TTobject
89   - ]
90   -
  31 + { name: 'resultId', type: 'string'},
  32 + { name: 'folderId', type: 'string'},
  33 + { name: 'processId', type: 'string'},
  34 + { name: 'timesrc', type: 'string'/*, defaultValue: amdaModel.AmdaTimeObject.inputTimeSrc[1] /*'Interval'*/ },
  35 + { name: 'startDate', type: 'date', defaultValue:Ext.Date.add(Ext.Date.clearTime(new Date()),Ext.Date.DAY,-1),
  36 + convert: function(value,rec) {
  37 + if (!Ext.isDate(value)) {
  38 + var valueString = new String(value);
  39 + var date = new Date(valueString.replace(/\-/g,'\/').replace(/[T|Z]/g,' '));
  40 + return date;
  41 + }
  42 + return value;
  43 + }
  44 + },
  45 + {
  46 + name: 'stopDate', type: 'date', defaultValue: Ext.Date.clearTime (new Date()), persist: false,
  47 + convert: function(value,rec) {
  48 + if (!Ext.isDate(value)){
  49 + var valueString = new String(value);
  50 + var date = new Date(valueString.replace(/\-/g,'\/').replace(/[T|Z]/g,' '));
  51 + return date;
  52 + }
  53 + return value;
  54 + }
  55 + },
  56 + {
  57 + name: 'durationDay', type: 'int',
  58 + convert: function(value, rec) {
  59 + var zoneOffset = rec.get('stopDate').getTimezoneOffset() - rec.get('startDate').getTimezoneOffset();
  60 +
  61 + return Ext.String.leftPad(Math.floor((rec.get('stopDate') - rec.get('startDate') - zoneOffset*60000)/86400000),4,'0');
  62 + }
  63 + },
  64 + {
  65 + name: 'durationHour', type: 'int',
  66 + convert: function(value, rec) {
  67 + var zoneOffset = rec.get('stopDate').getTimezoneOffset() - rec.get('startDate').getTimezoneOffset();
  68 + var diffH = (rec.get('stopDate') - rec.get('startDate') - zoneOffset*60000)/3600000 % 24;
  69 +
  70 + return Ext.String.leftPad(Math.floor(diffH), 2, '0');
  71 + }
  72 + },
  73 + {
  74 + name: 'durationMin', type: 'int',
  75 + convert: function(value, rec) {
  76 + var diffM = (rec.get('stopDate') - rec.get('startDate'))/60000 % 60;
  77 +
  78 + return Ext.String.leftPad(Math.floor(diffM), 2, '0');
  79 + }
  80 + },
  81 + {
  82 + name: 'durationSec', type: 'int',
  83 + convert: function(value, rec) {
  84 + var diffS = (rec.get('stopDate') - rec.get('startDate'))/1000 % 60;
  85 +
  86 + return Ext.String.leftPad(Math.floor(diffS), 2, '0');
  87 + }
  88 + },
  89 + { name: 'timeTables', defaultValue: null } // array of TTobject
  90 + ]
91 91 });
... ...
js/app/models/BkgJobNode.js
... ... @@ -10,9 +10,6 @@
10 10  
11 11 Ext.define('amdaModel.BkgJobNode', {
12 12 extend: 'amdaModel.ExecutableNode',
13   - requires: [
14   - 'amdaPlotObj.PlotRequestObject'
15   - ],
16 13 action : null,
17 14  
18 15 statics: {
... ...
js/app/models/DownloadNode.js
... ... @@ -62,90 +62,74 @@ Ext.define(&#39;amdaModel.DownloadNode&#39;, {
62 62 });
63 63 },
64 64  
65   - decodeObject: function(obj) {
66   - var myValues = new Object();
67   - myValues.list=[];
68   -
69   - if (!obj) {
70   - var fullObject = this.get('realLinkedNode').get('object');
71   - }
72   - else {
73   - var fullObject = obj;
74   - }
75   -
76   - var i = 0;
77   - fullObject.tabs().each(function (tab) {
78   - // only active tab
79   - if (tab.get('id') == fullObject.get('last-plotted-tab'))
80   - {
81   - tab.panels().each(function (panel) {
82   - panel.params().each(function (param) {
83   - var myParam = new Object();
84   - myParam.paramid = param.get('paramid');
85   - myParam.type = param.get('type');
86   - myParam['dim1-index'] = param.get('dim1-index');
87   - myParam['dim1-sum-type'] = param.get('dim1-sum-type');
88   - myParam['dim1-min-value'] = param.get('dim1-min-value');
89   - myParam['dim1-max-value'] = param.get('dim1-max-value');
90   - myParam['dim1-min-index'] = param.get('dim1-min-index');
91   - myParam['dim1-max-index'] = param.get('dim1-max-index');
92   - myParam['dim2-index'] = param.get('dim2-index');
93   - myParam['dim2-sum-type'] = param.get('dim2-sum-type');
94   - myParam['dim2-min-value'] = param.get('dim2-min-value');
95   - myParam['dim2-max-value'] = param.get('dim2-max-value');
96   - myParam['dim2-min-index'] = param.get('dim2-min-index');
97   - myParam['dim2-max-index'] = param.get('dim2-max-index');
98   - myParam.template_args = param.get('template_args');
99   - if (!param.get('plotonly')) {
100   - myValues.list[i] = myParam;
101   - ++i;
102   - }
103   - else
104   - alert('Parameter '+ myParam.paramid + ' is PlotOnly');
105   - });
106   - });
107   - if (tab.get('multi-plot-linked'))
108   - {
109   - var object = fullObject.data;
110   - }
111   - else
112   - {
113   - var object = tab.data;
114   - }
115   - myValues.timesrc = object.timesrc;
116   - // if there's at least one timeTable name into 'timeTables' collection
117   - if (myValues.timesrc == amdaModel.AmdaTimeObject.inputTimeSrc[0]
118   - && object.timeTables
119   - && object.timeTables.length ){
120   - // get complete timeTables collection
121   - var timeTables = object.timeTables;
122   - // init an empty array for timeTables
123   - myValues.timeTables=[];
124   - // for each interval record
125   - Ext.Array.each(timeTables, function(item, index, all){
126   - if (!item.$className) {
127   - myValues.timeTables[index] = {timeTableName : item.timeTableName, id : item.id};
128   - }
129   - // get Json simplified value
130   - else {
131   - myValues.timeTables[index] = item.getJsonValues();
132   - }
133   - });
134   - }
135   - else {
136   - myValues.startDate = object.startDate;
137   - myValues.stopDate = object.stopDate;
138   - myValues.durationDay = object.durationDay;
139   - myValues.durationHour = object.durationHour;
140   - myValues.durationMin = object.durationMin;
141   - myValues.durationSec = object.durationSec;
142   - }
143   - }
144   - });
145   -
146   - myValues.name = fullObject.get('name');
147   - return myValues;
148   - },
  65 + decodeObject: function(obj) {
  66 + var myValues = new Object();
  67 + myValues.list=[];
  68 +
  69 + if (!obj) {
  70 + var fullObject = this.get('realLinkedNode').get('object');
  71 + }
  72 + else {
  73 + var fullObject = obj;
  74 + }
  75 +
  76 + fullObject.panels().each(function (panel) {
  77 + panel.params().each(function (param) {
  78 + var myParam = new Object();
  79 + myParam.paramid = param.get('paramid');
  80 + myParam.type = param.get('type');
  81 + myParam['dim1-index'] = param.get('dim1-index');
  82 + myParam['dim1-sum-type'] = param.get('dim1-sum-type');
  83 + myParam['dim1-min-value'] = param.get('dim1-min-value');
  84 + myParam['dim1-max-value'] = param.get('dim1-max-value');
  85 + myParam['dim1-min-index'] = param.get('dim1-min-index');
  86 + myParam['dim1-max-index'] = param.get('dim1-max-index');
  87 + myParam['dim2-index'] = param.get('dim2-index');
  88 + myParam['dim2-sum-type'] = param.get('dim2-sum-type');
  89 + myParam['dim2-min-value'] = param.get('dim2-min-value');
  90 + myParam['dim2-max-value'] = param.get('dim2-max-value');
  91 + myParam['dim2-min-index'] = param.get('dim2-min-index');
  92 + myParam['dim2-max-index'] = param.get('dim2-max-index');
  93 + myParam.template_args = param.get('template_args');
  94 + if (!param.get('plotonly')) {
  95 + myValues.list.push(myParam);
  96 + }
  97 + else
  98 + alert('Parameter '+ myParam.paramid + ' is PlotOnly');
  99 + });
  100 + });
  101 + myValues.timesrc = fullObject.get('timesrc');
  102 + // if there's at least one timeTable name into 'timeTables' collection
  103 + if (myValues.timesrc == amdaModel.AmdaTimeObject.inputTimeSrc[0]
  104 + && fullObject.get('timeTables')
  105 + && fullObject.get('timeTables').length){
  106 + // get complete timeTables collection
  107 + var timeTables = fullObject.get('timeTables');
  108 + // init an empty array for timeTables
  109 + myValues.timeTables=[];
  110 + // for each interval record
  111 + Ext.Array.each(timeTables, function(item, index, all){
  112 + if (!item.$className) {
  113 + myValues.timeTables[index] = {timeTableName : item.timeTableName, id : item.id};
  114 + }
  115 + // get Json simplified value
  116 + else {
  117 + myValues.timeTables[index] = item.getJsonValues();
  118 + }
  119 + });
  120 + }
  121 + else {
  122 + myValues.startDate = fullObject.get('startDate');
  123 + myValues.stopDate = fullObject.get('stopDate');
  124 + myValues.durationDay = fullObject.get('durationDay');
  125 + myValues.durationHour = fullObject.get('durationHour');
  126 + myValues.durationMin = fullObject.get('durationMin');
  127 + myValues.durationSec = fullObject.get('durationSec');
  128 + }
  129 +
  130 + myValues.name = fullObject.get('name');
  131 + return myValues;
  132 + },
149 133  
150 134 encodeObject: function() {
151 135 },
... ...
js/app/models/InteractiveNode.js
... ... @@ -11,10 +11,6 @@
11 11 Ext.define('amdaModel.InteractiveNode', {
12 12 extend: 'amdaModel.AmdaNode',
13 13  
14   - requires: [
15   - 'amdaPlotObj.PlotRequestObject'
16   - ],
17   -
18 14 fields: [
19 15 {name: 'contextNode', type: 'amdaModel.AmdaNode', persist: false},
20 16 {name: 'objectDataModel', type: 'string', persist: false},
... ... @@ -52,7 +48,7 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, {
52 48 {
53 49 node.eachChild(function(n)
54 50 {
55   - if (!n.isLoaded() && !n.isRealLeaf())
  51 + if (!n.isLoaded() && !n.isLeaf())
56 52 {
57 53 nodesToLoad.push(n);
58 54 me.preloadTreeNode(n,nodesToLoad,onloaded);
... ... @@ -70,7 +66,7 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, {
70 66 {
71 67 records.forEach(function (record)
72 68 {
73   - if (!record.isLoaded() && !record.isRealLeaf())
  69 + if (!record.isLoaded() && !record.isLeaf())
74 70 {
75 71 nodesToLoad.push(record);
76 72 me.preloadTreeNode(record,nodesToLoad,onloaded);
... ... @@ -100,11 +96,6 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, {
100 96 }
101 97 },
102 98  
103   - isRealLeaf: function()
104   - {
105   - return this.isLeaf();
106   - },
107   -
108 99 /**
109 100 * this method is overriden into ExecutableNode to return true
110 101 */
... ... @@ -151,7 +142,7 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, {
151 142 */
152 143 rename: function(value,callBackFn)
153 144 {
154   - var dataToSend = {id : this.get('id'), old_name: this.modified.text, name: value, parent : this.data.parentId, leaf: this.isRealLeaf(), nodeType: this.get('nodeType')};
  145 + var dataToSend = {id : this.get('id'), old_name: this.modified.text, name: value, parent : this.data.parentId, leaf: this.isLeaf(), nodeType: this.get('nodeType')};
155 146 AmdaAction.renameObject(dataToSend, callBackFn);
156 147 },
157 148  
... ... @@ -160,7 +151,7 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, {
160 151 */
161 152 renameDD: function(parentId, callBackFn)
162 153 {
163   - var dataToSend = {id : this.get('id'), old_name: this.get('name'), name: this.get('name'), parent : parentId, leaf: this.isRealLeaf(), nodeType: this.get('nodeType')};
  154 + var dataToSend = {id : this.get('id'), old_name: this.get('name'), name: this.get('name'), parent : parentId, leaf: this.isLeaf(), nodeType: this.get('nodeType')};
164 155 AmdaAction.renameObject(dataToSend, callBackFn);
165 156 },
166 157  
... ... @@ -171,7 +162,7 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, {
171 162 */
172 163 isValidName : function(name, callBackFn)
173 164 {
174   - var dataToSend = {name: name, nodeType: this.get('nodeType'), leaf: this.isRealLeaf()};
  165 + var dataToSend = {name: name, nodeType: this.get('nodeType'), leaf: this.isLeaf()};
175 166 AmdaAction.validNameObject(dataToSend, callBackFn);
176 167 },
177 168  
... ... @@ -219,7 +210,12 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, {
219 210 // reload object into the view of corresponding Module
220 211 var me = this;
221 212 myDesktopApp.getLoadedModule(this.get('moduleId'), true, function (module) {
222   - module.getUiContent().setObject(me.get('object'));
  213 + if (!opt || !opt.plot) {
  214 + module.getUiContent().setObject(me.get('object'));
  215 + }
  216 + else {
  217 + module.getUiContent().reloadPlot(me);
  218 + }
223 219 });
224 220 }
225 221 else {
... ... @@ -459,16 +455,7 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, {
459 455 {
460 456 if (node.get('disable')) return;
461 457 myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.plot.id, true, function (module) {
462   - if (!myDesktopApp.desktop.getWindow(myDesktopApp.dynamicModules.plot.id)) {
463   - var request = Ext.create(amdaPlotObj.PlotRequestObject.$className);
464   - var newNode = Ext.create(amdaModel.PlotNode.$className, { object : request });
465   - // edit newNode into Plot Module with node as contextNode
466   - newNode.editInModule();
467   - if((node.get('globalStart') != null) && (node.get('globalStop') != null) && node.get('globalStart') != 'depending on mission' && node.get('isParameter')) {
468   - module.getUiContent().setTimeFromData(node.getTimeFromNode(node));
469   - }
470   - }
471   - module.getUiContent().addParameter(node);
  458 + module.addParameter(node);
472 459 });
473 460 },
474 461  
... ... @@ -530,7 +517,7 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, {
530 517  
531 518 deleteNode: function() {
532 519 // if the target is a directory
533   - if (!this.isRealLeaf()) {
  520 + if (!this.isLeaf()) {
534 521 // determine if this directory is empty before launching the delete confirmation method
535 522 this.isNotEmptyDir(this.confirmDirectoryDeletion);
536 523 // else (the target is a leaf)
... ... @@ -583,14 +570,14 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, {
583 570 */
584 571 realDelete : function()
585 572 {
586   - AmdaAction.deleteObject({id: this.get('id'), leaf: this.isRealLeaf(), nodeType: this.get('nodeType')}, function(res,e){
  573 + AmdaAction.deleteObject({id: this.get('id'), leaf: this.isLeaf(), nodeType: this.get('nodeType')}, function(res,e){
587 574 //TODO proper errors handling
588 575 // node deletion in tree
589 576 if (res) { // if success
590 577 if (res.id) {
591 578 //Ext.Msg.show({title:'Warning', msg: 'Requests with parameter '+node.data.text+' are deleted', icon: Ext.MessageBox.ERROR, buttons: Ext.Msg.OK});
592 579 if (this.parentNode) {
593   - if (this.isRealLeaf()){
  580 + if (this.isLeaf()){
594 581 var moduleId = this.get('moduleId');
595 582 // if really interactive node
596 583 if (moduleId) {
... ...
js/app/models/MultiplotNode.js 0 โ†’ 100644
... ... @@ -0,0 +1,25 @@
  1 +/**
  2 + * Project : AMDA-NG4
  3 + * Name : MultiplotNode.js
  4 + * @class amdaModel.MutiplotNode
  5 + * @extends amdaModel.ExecutableNode
  6 + * @brief Basic Model of Node corresponding to a multi-plot request
  7 + * @author Benjamin Renard
  8 + */
  9 +
  10 +Ext.define('amdaModel.MultiplotNode', {
  11 + extend: 'amdaModel.ExecutableNode',
  12 +
  13 + statics: {
  14 + nodeType: 'mutiplot'
  15 + },
  16 +
  17 + constructor : function(config){
  18 + this.callParent(arguments);
  19 + this.set('moduleId',myDesktopApp.dynamicModules.plot.id);
  20 + this.set('objectDataModel','amdaPlotObj.MultiplotRequestObject');
  21 + this.set('nodeType',this.self.nodeType);
  22 + this.set('leaf', true);
  23 + }
  24 +
  25 +});
... ...
js/app/models/PlotNode.js
... ... @@ -8,49 +8,17 @@
8 8 */
9 9  
10 10 Ext.define('amdaModel.PlotNode', {
11   - extend: 'amdaModel.ExecutableNode',
12   -
13   - fields : [
14   - {name : 'tabs', type:'auto', defaultValue:false, persist: false}
15   - ],
  11 + extend: 'amdaModel.ExecutableNode',
16 12  
17 13 statics: {
18 14 nodeType: 'request'
19 15 },
20 16  
21   - requires:[
22   - 'amdaModel.PlotTabNode'
23   - ],
24   -
25 17 constructor : function(config){
26 18 this.callParent(arguments);
27 19 this.set('moduleId',myDesktopApp.dynamicModules.plot.id);
28 20 this.set('objectDataModel','amdaPlotObj.PlotRequestObject');
29 21 this.set('nodeType',this.self.nodeType);
30   - if (this.get('leaf')) {
31   - this.updateTabs(this.get('tabs'));
32   - }
33   - },
34   -
35   - updateTabs : function(tabs) {
36   - if (tabs) {
37   - var oneTab = (tabs.length == 1);
38   - this.set('leaf', oneTab);
39   - this.set('iconCls', oneTab ? 'icon-plot-page' : 'icon-plot-pages');
40   - this.removeAll();
41   - if (tabs.length > 1) {
42   - var me = this;
43   - Ext.Array.each(tabs, function(tab) {
44   - var tabNode = new amdaModel.PlotTabNode({text: tab.name, tabid: tab.id});
45   - me.appendChild(tabNode);
46   - });
47   - }
48   - this.set('tabs', tabs);
49   - }
50   - },
51   -
52   - specialUpdate : function(res) {
53   - this.updateTabs(res.tabs);
54 22 },
55 23  
56 24 allMenuItems : function() {
... ... @@ -76,10 +44,6 @@ Ext.define(&#39;amdaModel.PlotNode&#39;, {
76 44 }, {
77 45 fnId : 'leaf-deleteNode',
78 46 text : 'Delete Request'
79   - }, {
80   - fnId : 'leaf-insertTabs',
81   - text : 'Insert in current Plot Request'
82   -
83 47 }];
84 48  
85 49 return menuItems;
... ... @@ -128,35 +92,33 @@ Ext.define(&#39;amdaModel.PlotNode&#39;, {
128 92 case 'deleteMulti':
129 93 this.deleteMulti();
130 94 break;
131   - case 'insertTabs':
132   - this.insertPlotTabsRequest();
133 95 default:
134 96 break;
135 97 }
136 98 },
137 99  
138   - isRealLeaf: function()
  100 + //Override editInModule
  101 + editInModule : function (contextNode, onReady)
139 102 {
140   - var isFolder = (!this.isLeaf()) && (this.get('tabs') === false);
141   - return !isFolder;
  103 + // set the contextNode of this node
  104 + this.set('contextNode',contextNode);
  105 +
  106 + var me = this;
  107 + myDesktopApp.getLoadedModule(this.get('moduleId'),true, function (module) {
  108 + module.editPlot(me);
  109 + });
142 110 },
143 111  
144   - insertPlotTabsRequest: function() {
145   - var me = this;
146   - AmdaAction.getObject(me.get('id'), me.get('nodeType'), function (result,remoteEvent) {
147   - var paramObj = Ext.create(me.get('objectDataModel'), result);
148   - myDesktopApp.getLoadedModule(me.get('moduleId'), true, function (module) {
149   - module.createWindow(function () {
150   - var uiContent = module.getUiContent();
151   - if (uiContent != null) {
152   - paramObj.tabs().each(function (tab) {
153   - var tabData = tab.getJsonValues();
154   - uiContent.insertPlotTab(tabData);
155   - });
156   - }
157   - });
158   - });
159   - });
160   - }
161   -
  112 + //Override rename
  113 + rename: function(value,callBackFn)
  114 + {
  115 + var me = this;
  116 + var dataToSend = {id : this.get('id'), old_name: this.modified.text, name: value, parent : this.data.parentId, leaf: this.isLeaf(), nodeType: this.get('nodeType')};
  117 + AmdaAction.renameObject(dataToSend, function(result) {
  118 + callBackFn(result);
  119 + myDesktopApp.getLoadedModule(me.get('moduleId'),true, function (module) {
  120 + module.syncAfterRename(me);
  121 + });
  122 + });
  123 + }
162 124 });
... ...
js/app/models/PlotObjects/MultiplotRequestObject.js 0 โ†’ 100644
... ... @@ -0,0 +1,87 @@
  1 +/**
  2 + * Project  : AMDA-NG
  3 + * Name : MultiplotRequestObject.js
  4 + * @class amdaPlotObj.MutiplotRequestObject
  5 + * @extends amdaModel.AmdaTimeObject
  6 + * @brief Multi-Plot Request Business Object Definition
  7 + * @author Benjamin Renard
  8 + * @version $Id: MultiplotRequestObject.js benjamin $
  9 + ******************************************************************************
  10 + * FT Id : Date : Name - Description
  11 + ******************************************************************************
  12 + * : :28/02/2020: BRE - file creation
  13 + */
  14 +
  15 +
  16 +Ext.define('amdaPlotObj.MultiplotRequestObject', {
  17 + extend: 'amdaModel.AmdaTimeObject',
  18 + idProperty: 'id',
  19 +
  20 + requires: [
  21 + 'amdaModel.PlotNode',
  22 + 'amdaPlotObj.PlotRequestObject'
  23 + ],
  24 +
  25 + hasMany: {
  26 + model : 'amdaModel.PlotNode',
  27 + name : 'plots',
  28 + associationKey:'plots'
  29 + },
  30 +
  31 + constructor: function(){
  32 + var me = this;
  33 + me.callParent(arguments);
  34 + },
  35 +
  36 + isDirty: function() {
  37 + var dirty = false;
  38 + this.plots().each(function(plotNode) {
  39 + var plotObject = plotNode.get('object');
  40 + if (plotObject && (plotObject.get('id') != '') && plotObject.dirty) {
  41 + dirty = true;
  42 + }
  43 + });
  44 + return dirty;
  45 + },
  46 +
  47 + createNewPlot: function() {
  48 + var plotObject = Ext.create('amdaPlotObj.PlotRequestObject');
  49 + return this.createNewPlotFromObject(plotObject);
  50 + },
  51 +
  52 + duplicatePlot: function(plotNode) {
  53 + var me = this;
  54 + var newPlotNode = null;
  55 + this.plots().each(function(node, index) {
  56 + if (node == plotNode) {
  57 + newPlotNode = Ext.create('amdaModel.PlotNode', {
  58 + leaf : true
  59 + });
  60 + var data = plotNode.get('object').getJsonValues();
  61 + newPlotNode.set('object', Ext.create('amdaPlotObj.PlotRequestObject', data));
  62 + plotNode.get('object').reject();
  63 + me.plots().remove(plotNode);
  64 + me.plots().insert(index, [newPlotNode]);
  65 + }
  66 + });
  67 + return newPlotNode;
  68 + },
  69 +
  70 + createNewPlotFromObject: function(plotObject) {
  71 + var plotNode = Ext.create('amdaModel.PlotNode', {
  72 + leaf : true
  73 + });
  74 + plotNode.set('object',plotObject);
  75 + this.plots().add(plotNode);
  76 + return this.plots().getAt(this.plots().count()-1);
  77 + },
  78 +
  79 + removePlotByInternalId: function(internalId) {
  80 + var plotNode = this.plots().data.getByKey(internalId);
  81 + if (plotNode)
  82 + this.plots().remove(plotNode);
  83 + },
  84 +
  85 + addPlot: function(plotNode) {
  86 + }
  87 +});
... ...
js/app/models/PlotObjects/PlotRequestObject.js
... ... @@ -5,11 +5,12 @@
5 5 * @extends amdaModel.AmdaTimeObject
6 6 * @brief Plot Request Business Object Definition
7 7 * @author Benjamin Renard
8   - * @version $Id: PlotRequestObject.js benjamin $
  8 + * @version $Id: PlotTabObject.js benjamin $
9 9 ******************************************************************************
10 10 * FT Id : Date : Name - Description
11 11 ******************************************************************************
12   - * : :21/07/2015: BRE - file creation
  12 + * : :22/07/2015: BRE - file creation
  13 + * 20/03/2020: BRE - full rework
13 14 */
14 15  
15 16  
... ... @@ -19,122 +20,256 @@ Ext.define(&#39;amdaPlotObj.PlotRequestObject&#39;, {
19 20  
20 21 requires: [
21 22 'amdaPlotObj.PlotObjectConfig',
22   - 'amdaPlotObj.PlotTabObject'
  23 + 'amdaPlotObj.PlotPanelObject',
  24 + 'amdaPlotObj.PlotLayoutVerticalObject',
  25 + 'amdaPlotObj.PlotLayoutAutoObject',
  26 + 'amdaPlotObj.PlotLayoutManualObject'
23 27 ],
24 28  
25 29 fields : [
26   - {name: 'id', type:'string'},
  30 + {name: 'tab-index', type: 'int', defaultValue: 0, persist: false},
  31 + {name: 'tab-title', type: 'string', defaultValue: '', persist: false},
  32 +
27 33 {name: 'file-format', type: 'string'},
28 34 {name: 'file-output', type: 'string'},
29 35 {name: 'file-prefix', type: 'string'},
30 36 {name: 'one-file-per-interval', type: 'boolean'},
31   - {name: 'last-plotted-tab', type: 'int', defaultValue: 0},
32   - {name: 'last-tab-id', type: 'int', defaultValue: 0},
33   - {name: 'active-tab-id', type: 'int', defaultValue: 1}
  37 +
  38 + {name: 'tree-full-view', type: 'boolean'},
  39 + {name: 'page-node-state', type: 'int', defaultValue: 2}, //0 : collapsed, 1 : expanded, 2 : not set
  40 + {name: 'panels-node-state', type: 'int', defaultValue: 2}, //0 : collapsed, 1 : expanded, 2 : not set
  41 +
  42 + {name: 'page-title-text', type: 'string'},
  43 + {name: 'page-title-color', type: 'string'},
  44 + {name: 'page-title-position', type: 'string'},
  45 + {name: 'page-title-alignment', type: 'string'},
  46 + {name: 'page-title-font-activated', type: 'boolean'},
  47 + {name: 'page-title-font-name', type: 'string'},
  48 + {name: 'page-title-font-size', type: 'int'},
  49 + {name: 'page-title-font-bold', type: 'boolean'},
  50 + {name: 'page-title-font-italic', type: 'boolean'},
  51 + {name: 'page-margins-activated', type: 'boolean'},
  52 + {name: 'page-margin-x', type: 'float'},
  53 + {name: 'page-margin-y', type: 'float'},
  54 + {name: 'page-mode', type: 'string'},
  55 + {name: 'page-orientation', type: 'string'},
  56 + {name: 'page-dimension', type: 'string'},
  57 + {name: 'page-superpose-mode', type: 'boolean'},
  58 + {name: 'page-font-activated', type: 'boolean'},
  59 + {name: 'page-font-name', type: 'string'},
  60 + {name: 'page-font-size', type: 'int'},
  61 + {name: 'page-font-bold', type: 'boolean'},
  62 + {name: 'page-font-italic', type: 'boolean'},
  63 + {name: 'page-layout-type', type: 'string'},
  64 + {name: 'page-layout-object', type: 'auto', defaultValue: null},
  65 + {name: 'last-panel-id', type: 'int', defaultValue: 0}
34 66 ],
35 67  
36   - hasMany: {
37   - model : 'amdaPlotObj.PlotTabObject',
38   - name : 'tabs',
39   - associationKey:'tabs'
40   - },
  68 + associations : [
  69 + {
  70 + type : 'hasMany',
  71 + model : 'amdaPlotObj.PlotPanelObject',
  72 + name : 'panels'
  73 + }
  74 + ],
41 75  
42 76 constructor: function(){
43   - var me = this;
44   - me.callParent(arguments);
45   - if ((arguments.length > 0) && arguments[0] && arguments[0].tabs)
  77 + var me = this;
  78 + me.callParent(arguments);
  79 + if ((arguments.length > 0) && arguments[0])
46 80 {
47   - if (arguments[0].tabs)
48   - me.loadTabs(arguments[0].tabs);
  81 + if (arguments[0].panels)
  82 + me.loadPanels(arguments[0].panels);
  83 + if (arguments[0]['page-layout-object'])
  84 + me.loadLayoutObject(arguments[0]['page-layout-object']);
49 85 }
50 86 else
51 87 {
52 88 //new object, set default fields values
53 89 me.setDefaultValues();
54   - //New object, force the creation of the first tab
55   - me.createNewTab();
56 90 }
  91 + this.dirty = false;
57 92 },
58 93  
59   - loadTabs: function(tabs)
  94 + loadPanels: function(panels)
60 95 {
61   - this.tabs().loadData(tabs);
  96 + this.panels().loadData(panels);
  97 + this.updatePanelIndex();
62 98 },
63 99  
64   - setDefaultValues: function()
  100 + loadLayoutObject: function(layout)
65 101 {
66   - this.set('file-format', amdaPlotObj.PlotObjectConfig.defaultValues.file.format);
67   - this.set('file-output', amdaPlotObj.PlotObjectConfig.defaultValues.file.output);
68   - this.set('file-prefix', '');
69   - this.set('one-file-per-interval', amdaPlotObj.PlotObjectConfig.defaultValues.file.oneFilePerInterval);
70   - this.set('last-plotted-tab', 0);
71   - this.set('name', '');
  102 + this.set('page-layout-object', this.createLayoutByType(this.get('page-layout-type'), layout));
  103 + if (this.get('page-layout-object') != null)
  104 + this.get('page-layout-object').dirty = false;
72 105 },
73 106  
74   - createNewTab: function() {
75   - this.set('last-tab-id', this.get('last-tab-id') + 1);
76   - var data = {id: this.get('last-tab-id')};
77   - var applyDefault = true;
78   - if ((arguments.length > 0) && arguments[0]) {
79   - data = arguments[0];
80   - data['id'] = this.get('last-tab-id');
81   - applyDefault = false;
82   - }
83   - var recs = this.tabs().add(data);
84   - if (applyDefault) {
85   - recs[0].setDefaultValues();
86   - }
  107 + createNewPanel: function() {
  108 + this.set('last-panel-id', this.get('last-panel-id') + 1);
  109 + var recs = this.panels().add({id : this.get('last-panel-id')});
  110 + recs[0].setDefaultValues();
87 111 this.dirty = true;
88   - return recs[0];
  112 + this.updatePanelIndex();
  113 + return recs[0];
89 114 },
90 115  
91   - removeTabById: function(tabId) {
92   - //Retrieve tab record
93   - var tabRecord = this.tabs().getById(tabId);
94   - if (tabRecord == null)
  116 + removePanelById: function(panelId) {
  117 + //Retrieve panel record
  118 + var panelRecord = this.panels().getById(panelId);
  119 + if (panelRecord == null)
95 120 return false;
96   - this.tabs().remove(tabRecord);
  121 + this.panels().remove(panelRecord);
97 122 this.dirty = true;
  123 + this.updatePanelIndex();
98 124 return true;
99 125 },
100 126  
101   - isDirty : function()
  127 + updatePanelIndex: function() {
  128 + this.panels().each(function(panel, index) {
  129 + panel.set('panel-index', index);
  130 + });
  131 + },
  132 +
  133 + createLayoutByType : function(layoutType, data)
102 134 {
103   - if (this.get('id') == '')
104   - return false;
  135 + //Create layout object in relation with the type
  136 + switch (layoutType)
  137 + {
  138 + case 'vertical' :
  139 + return new amdaPlotObj.PlotLayoutVerticalObject(data);
  140 + case 'auto' :
  141 + return new amdaPlotObj.PlotLayoutAutoObject(data);
  142 + case 'manual' :
  143 + return new amdaPlotObj.PlotLayoutManualObject(data);
  144 + default :
  145 + return null;
  146 + }
  147 + },
  148 +
  149 + setLayout: function(layoutType)
  150 + {
  151 + if (layoutType == this.get('page-layout-type'))
  152 + return;
  153 +
  154 + this.set('page-layout-type', layoutType);
  155 + this.set('page-layout-object', this.createLayoutByType(layoutType));
  156 + },
  157 +
  158 + setDefaultValues: function()
  159 + {
  160 + this.set('file-format', amdaPlotObj.PlotObjectConfig.defaultValues.file.format);
  161 + this.set('file-output', amdaPlotObj.PlotObjectConfig.defaultValues.file.output);
  162 + this.set('file-prefix', '');
  163 + this.set('one-file-per-interval', amdaPlotObj.PlotObjectConfig.defaultValues.file.oneFilePerInterval);
  164 + this.set('name', '');
  165 +
  166 + this.set('tree-full-view', amdaPlotObj.PlotObjectConfig.defaultValues.tree.fullView);
105 167  
  168 + this.set('page-title-text', '');
  169 + this.set('page-title-color', amdaPlotObj.PlotObjectConfig.defaultValues.page.title.color);
  170 + this.set('page-title-position', amdaPlotObj.PlotObjectConfig.defaultValues.page.title.position);
  171 + this.set('page-title-alignment', amdaPlotObj.PlotObjectConfig.defaultValues.page.title.alignment);
  172 +
  173 + this.set('page-title-font-activated', false);
  174 + this.set('page-title-font-name', amdaPlotObj.PlotObjectConfig.defaultValues.page.font.name);
  175 + this.set('page-title-font-size', amdaPlotObj.PlotObjectConfig.defaultValues.page.font.size);
  176 + this.set('page-title-font-bold', false);
  177 + this.set('page-title-font-italic', false);
  178 +
  179 + this.set('page-margins-activated', false);
  180 + this.set('page-margin-x', amdaPlotObj.PlotObjectConfig.defaultValues.page.xMargin);
  181 + this.set('page-margin-y', amdaPlotObj.PlotObjectConfig.defaultValues.page.yMargin);
  182 + this.set('page-mode', amdaPlotObj.PlotObjectConfig.defaultValues.page.mode);
  183 + this.set('page-orientation', amdaPlotObj.PlotObjectConfig.defaultValues.page.orientation);
  184 + this.set('page-dimension', amdaPlotObj.PlotObjectConfig.defaultValues.page.dimension);
  185 + this.set('page-superpose-mode', false);
  186 + this.set('page-font-activated', false);
  187 + this.set('page-font-name', amdaPlotObj.PlotObjectConfig.defaultValues.page.font.name);
  188 + this.set('page-font-size', amdaPlotObj.PlotObjectConfig.defaultValues.page.font.size);
  189 + this.set('page-font-bold', false);
  190 + this.set('page-font-italic', false);
  191 +
  192 + this.setLayout(amdaPlotObj.PlotObjectConfig.defaultValues.page.layout.type);
  193 + },
  194 +
  195 + getPageShortInfo : function()
  196 + {
  197 + var dimension = amdaPlotObj.PlotObjectConfig.getValueByKey(amdaPlotObj.PlotObjectConfig.availablePageDimensions, this.get('page-dimension'));
  198 + var orientation = amdaPlotObj.PlotObjectConfig.getValueByKey(amdaPlotObj.PlotObjectConfig.availablePageOrientations, this.get('page-orientation'));
  199 +
  200 + var info = dimension+', '+orientation;
  201 + if (this.get('page-superpose-mode'))
  202 + info += ', Epoch superposed mode';
  203 + return info;
  204 + },
  205 +
  206 + getLayoutShortInfo : function()
  207 + {
  208 + var type = amdaPlotObj.PlotObjectConfig.getValueByKey(amdaPlotObj.PlotObjectConfig.availablePageLayouts, this.get('page-layout-type'));
  209 + return type;
  210 + },
  211 +
  212 + isDirty : function()
  213 + {
106 214 if (this.dirty)
107 215 return true;
108 216  
  217 + if (this.get('page-layout-object') != null)
  218 + if (this.get('page-layout-object').dirty)
  219 + return true;
  220 +
109 221 var d = false;
110   - this.tabs().each(function (tab, index) {
111   - if (tab.isDirty())
  222 + this.panels().each(function (panel, index) {
  223 + if (panel.isDirty())
112 224 d = true;
113 225 });
114 226 return d;
115 227 },
116 228  
117   - getJsonValues : function(hasId)
  229 + getJsonValues : function()
118 230 {
119 231 var requestValues = new Object();
  232 +
  233 + requestValues['nodeType'] = 'request';
  234 + requestValues['leaf'] = true;
120 235  
121   - requestValues['nodeType'] = 'request';
122   -
123   - if (hasId) {
124   - requestValues['id'] = this.get('id');
125   - }
126   -
127   - requestValues['leaf'] = true;
  236 + requestValues['id'] = this.get('id');
  237 + requestValues['tab-index'] = this.get('tab-index');
  238 + requestValues['tab-title'] = this.get('tab-title');
  239 + requestValues['name'] = this.get('name');
  240 +
  241 + requestValues['file-format'] = this.get('file-format');
  242 + requestValues['file-output'] = this.get('file-output');
  243 + requestValues['file-prefix'] = this.get('file-prefix');
  244 + requestValues['one-file-per-interval'] = this.get('one-file-per-interval');
  245 +
  246 + requestValues['tree-full-view'] = this.get('tree-full-view');
  247 + requestValues['page-node-state'] = this.get('page-node-state');
  248 + requestValues['panels-node-state'] = this.get('panels-node-state');
  249 +
  250 + requestValues['page-title-text'] = this.get('page-title-text');
  251 + requestValues['page-title-color'] = this.get('page-title-color');
  252 + requestValues['page-title-position'] = this.get('page-title-position');
  253 + requestValues['page-title-alignment'] = this.get('page-title-alignment');
  254 + requestValues['page-title-font-activated'] = this.get('page-title-font-activated');
  255 + requestValues['page-title-font-name'] = this.get('page-title-font-name');
  256 + requestValues['page-title-font-size'] = this.get('page-title-font-size');
  257 + requestValues['page-title-font-bold'] = this.get('page-title-font-bold');
  258 + requestValues['page-title-font-italic'] = this.get('page-title-font-italic');
  259 + requestValues['page-margins-activated'] = this.get('page-margins-activated');
  260 + requestValues['page-margin-x'] = this.get('page-margin-x');
  261 + requestValues['page-margin-y'] = this.get('page-margin-y');
  262 + requestValues['page-mode'] = this.get('page-mode');
  263 + requestValues['page-orientation'] = this.get('page-orientation');
  264 + requestValues['page-dimension'] = this.get('page-dimension');
  265 + requestValues['page-superpose-mode'] = this.get('page-superpose-mode');
  266 + requestValues['page-font-activated'] = this.get('page-font-activated');
  267 + requestValues['page-font-name'] = this.get('page-font-name');
  268 + requestValues['page-font-size'] = this.get('page-font-size');
  269 + requestValues['page-font-bold'] = this.get('page-font-bold');
  270 + requestValues['page-font-italic'] = this.get('page-font-italic');
128 271  
129   - requestValues['file-format'] = this.get('file-format');
130   - requestValues['file-output'] = this.get('file-output');
131   - requestValues['file-prefix'] = this.get('file-prefix');
132   - requestValues['one-file-per-interval'] = this.get('one-file-per-interval');
133   - requestValues['last-plotted-tab'] = this.get('last-plotted-tab');
134   - requestValues['name'] = this.get('name');
135   -
136   - requestValues['timesrc'] = this.get('timesrc');
137   -
  272 + requestValues['timesrc'] = this.get('timesrc');
138 273 // if there's at least one timeTable name into 'timeTables' collection
139 274 if (this.get('timesrc') == amdaModel.AmdaTimeObject.inputTimeSrc[0] && this.get('timeTables') && this.get('timeTables').length){
140 275 // get complete timeTables collection
... ... @@ -152,23 +287,26 @@ Ext.define(&#39;amdaPlotObj.PlotRequestObject&#39;, {
152 287 }
153 288 });
154 289 } else {
155   - requestValues['startDate'] = this.get('startDate');
156   - requestValues['stopDate'] = this.get('stopDate');
157   - requestValues['durationDay'] = this.get('durationDay');
158   - requestValues['durationHour'] = this.get('durationHour');
159   - requestValues['durationMin'] = this.get('durationMin');
160   - requestValues['durationSec'] = this.get('durationSec');
161   - }
  290 + requestValues['startDate'] = this.get('startDate');
  291 + requestValues['stopDate'] = this.get('stopDate');
  292 + requestValues['durationDay'] = this.get('durationDay');
  293 + requestValues['durationHour'] = this.get('durationHour');
  294 + requestValues['durationMin'] = this.get('durationMin');
  295 + requestValues['durationSec'] = this.get('durationSec');
  296 + }
162 297  
163   - requestValues['tabs'] = [];
164   -
165   - this.tabs().each(function (tab, index) {
166   - requestValues['tabs'][index] = tab.getJsonValues();
167   - });
168   -
169   - requestValues['active-tab-id'] = this.get('active-tab-id');
170   - requestValues['last-tab-id'] = this.get('last-tab-id');
171   -
172   - return requestValues;
  298 + requestValues['page-layout-type'] = this.get('page-layout-type');
  299 + if (this.get('page-layout-object') != null)
  300 + requestValues['page-layout-object'] = this.get('page-layout-object').getJsonValues();
  301 +
  302 + requestValues['panels'] = [];
  303 +
  304 + this.panels().each(function (panel, index) {
  305 + requestValues['panels'][index] = panel.getJsonValues();
  306 + });
  307 +
  308 + requestValues['last-panel-id'] = this.get('last-panel-id');
  309 +
  310 + return requestValues;
173 311 }
174 312 });
... ...
js/app/models/PlotObjects/PlotTabObject.js deleted
... ... @@ -1,294 +0,0 @@
1   -/**
2   - * Project  : AMDA-NG
3   - * Name : PlotTabObject.js
4   - * @class amdaPlotObj.PlotTabObject
5   - * @extends amdaModel.AmdaTimeObject
6   - * @brief Plot Tab Business Object Definition
7   - * @author Benjamin Renard
8   - * @version $Id: PlotTabObject.js benjamin $
9   - ******************************************************************************
10   - * FT Id : Date : Name - Description
11   - ******************************************************************************
12   - * : :22/07/2015: BRE - file creation
13   - */
14   -
15   -
16   -Ext.define('amdaPlotObj.PlotTabObject', {
17   - extend: 'amdaModel.AmdaTimeObject',
18   - idProperty: 'id',
19   -
20   - requires: [
21   - 'amdaPlotObj.PlotObjectConfig',
22   - 'amdaPlotObj.PlotPanelObject',
23   - 'amdaPlotObj.PlotLayoutVerticalObject',
24   - 'amdaPlotObj.PlotLayoutAutoObject',
25   - 'amdaPlotObj.PlotLayoutManualObject'
26   - ],
27   -
28   - fields : [
29   - {name: 'id', type: 'int'},
30   - {name: 'tab-name', type: 'string', defaultValue: ''},
31   - {name: 'tree-full-view', type: 'boolean'},
32   - {name: 'multi-plot-linked', type: 'boolean'},
33   - {name: 'page-node-state', type: 'int', defaultValue: 2}, //0 : collapsed, 1 : expanded, 2 : not set
34   - {name: 'panels-node-state', type: 'int', defaultValue: 2}, //0 : collapsed, 1 : expanded, 2 : not set
35   - {name: 'page-title-text', type: 'string'},
36   - {name: 'page-title-color', type: 'string'},
37   - {name: 'page-title-position', type: 'string'},
38   - {name: 'page-title-alignment', type: 'string'},
39   - {name: 'page-title-font-activated', type: 'boolean'},
40   - {name: 'page-title-font-name', type: 'string'},
41   - {name: 'page-title-font-size', type: 'int'},
42   - {name: 'page-title-font-bold', type: 'boolean'},
43   - {name: 'page-title-font-italic', type: 'boolean'},
44   - {name: 'page-margins-activated', type: 'boolean'},
45   - {name: 'page-margin-x', type: 'float'},
46   - {name: 'page-margin-y', type: 'float'},
47   - {name: 'page-mode', type: 'string'},
48   - {name: 'page-orientation', type: 'string'},
49   - {name: 'page-dimension', type: 'string'},
50   - {name: 'page-superpose-mode', type: 'boolean'},
51   - {name: 'page-font-activated', type: 'boolean'},
52   - {name: 'page-font-name', type: 'string'},
53   - {name: 'page-font-size', type: 'int'},
54   - {name: 'page-font-bold', type: 'boolean'},
55   - {name: 'page-font-italic', type: 'boolean'},
56   - {name: 'page-layout-type', type: 'string'},
57   - {name: 'page-layout-object', type: 'auto', defaultValue: null},
58   - {name: 'last-panel-id', type: 'int', defaultValue: 0}
59   - ],
60   -
61   - associations : [
62   - {
63   - type : 'hasMany',
64   - model : 'amdaPlotObj.PlotPanelObject',
65   - name : 'panels'
66   - },
67   - {
68   - type : 'belongsTo',
69   - model : 'amdaPlotObj.PlotRequestObject'
70   - }
71   - ],
72   -
73   - constructor: function(){
74   - var me = this;
75   - me.callParent(arguments);
76   - if ((arguments.length > 0) && arguments[0])
77   - {
78   - if (arguments[0].panels)
79   - me.loadPanels(arguments[0].panels);
80   - if (arguments[0]['page-layout-object'])
81   - me.loadLayoutObject(arguments[0]['page-layout-object']);
82   - }
83   - else
84   - {
85   - //new object, set default fields values
86   - me.setDefaultValues();
87   - }
88   - this.dirty = false;
89   - },
90   -
91   - loadPanels: function(panels)
92   - {
93   - this.panels().loadData(panels);
94   - this.updatePanelIndex();
95   - },
96   -
97   - loadLayoutObject: function(layout)
98   - {
99   - this.set('page-layout-object', this.createLayoutByType(this.get('page-layout-type'), layout));
100   - if (this.get('page-layout-object') != null)
101   - this.get('page-layout-object').dirty = false;
102   - },
103   -
104   - createNewPanel: function() {
105   - this.set('last-panel-id', this.get('last-panel-id') + 1);
106   - var recs = this.panels().add({id : this.get('last-panel-id')});
107   - recs[0].setDefaultValues();
108   - this.dirty = true;
109   - this.updatePanelIndex();
110   - return recs[0];
111   - },
112   -
113   - removePanelById: function(panelId) {
114   - //Retrieve panel record
115   - var panelRecord = this.panels().getById(panelId);
116   - if (panelRecord == null)
117   - return false;
118   - this.panels().remove(panelRecord);
119   - this.dirty = true;
120   - this.updatePanelIndex();
121   - return true;
122   - },
123   -
124   - updatePanelIndex: function() {
125   - this.panels().each(function(panel, index) {
126   - panel.set('panel-index', index);
127   - });
128   - },
129   -
130   - createLayoutByType : function(layoutType, data)
131   - {
132   - //Create layout object in relation with the type
133   - switch (layoutType)
134   - {
135   - case 'vertical' :
136   - return new amdaPlotObj.PlotLayoutVerticalObject(data);
137   - case 'auto' :
138   - return new amdaPlotObj.PlotLayoutAutoObject(data);
139   - case 'manual' :
140   - return new amdaPlotObj.PlotLayoutManualObject(data);
141   - default :
142   - return null;
143   - }
144   - },
145   -
146   - setLayout: function(layoutType)
147   - {
148   - if (layoutType == this.get('page-layout-type'))
149   - return;
150   -
151   - this.set('page-layout-type', layoutType);
152   - this.set('page-layout-object', this.createLayoutByType(layoutType));
153   - },
154   -
155   - setDefaultValues: function()
156   - {
157   - this.set('tree-full-view', amdaPlotObj.PlotObjectConfig.defaultValues.tree.fullView);
158   -
159   - this.set('multi-plot-linked', false);
160   -
161   - this.set('page-title-text', '');
162   - this.set('page-title-color', amdaPlotObj.PlotObjectConfig.defaultValues.page.title.color);
163   - this.set('page-title-position', amdaPlotObj.PlotObjectConfig.defaultValues.page.title.position);
164   - this.set('page-title-alignment', amdaPlotObj.PlotObjectConfig.defaultValues.page.title.alignment);
165   -
166   - this.set('page-title-font-activated', false);
167   - this.set('page-title-font-name', amdaPlotObj.PlotObjectConfig.defaultValues.page.font.name);
168   - this.set('page-title-font-size', amdaPlotObj.PlotObjectConfig.defaultValues.page.font.size);
169   - this.set('page-title-font-bold', false);
170   - this.set('page-title-font-italic', false);
171   -
172   - this.set('page-margins-activated', false);
173   - this.set('page-margin-x', amdaPlotObj.PlotObjectConfig.defaultValues.page.xMargin);
174   - this.set('page-margin-y', amdaPlotObj.PlotObjectConfig.defaultValues.page.yMargin);
175   - this.set('page-mode', amdaPlotObj.PlotObjectConfig.defaultValues.page.mode);
176   - this.set('page-orientation', amdaPlotObj.PlotObjectConfig.defaultValues.page.orientation);
177   - this.set('page-dimension', amdaPlotObj.PlotObjectConfig.defaultValues.page.dimension);
178   - this.set('page-superpose-mode', false);
179   - this.set('page-font-activated', false);
180   - this.set('page-font-name', amdaPlotObj.PlotObjectConfig.defaultValues.page.font.name);
181   - this.set('page-font-size', amdaPlotObj.PlotObjectConfig.defaultValues.page.font.size);
182   - this.set('page-font-bold', false);
183   - this.set('page-font-italic', false);
184   -
185   - this.setLayout(amdaPlotObj.PlotObjectConfig.defaultValues.page.layout.type);
186   - },
187   -
188   - getPageShortInfo : function()
189   - {
190   - var dimension = amdaPlotObj.PlotObjectConfig.getValueByKey(amdaPlotObj.PlotObjectConfig.availablePageDimensions, this.get('page-dimension'));
191   - var orientation = amdaPlotObj.PlotObjectConfig.getValueByKey(amdaPlotObj.PlotObjectConfig.availablePageOrientations, this.get('page-orientation'));
192   -
193   - var info = dimension+', '+orientation;
194   - if (this.get('page-superpose-mode'))
195   - info += ', Epoch superposed mode';
196   - return info;
197   - },
198   -
199   - getLayoutShortInfo : function()
200   - {
201   - var type = amdaPlotObj.PlotObjectConfig.getValueByKey(amdaPlotObj.PlotObjectConfig.availablePageLayouts, this.get('page-layout-type'));
202   - return type;
203   - },
204   -
205   - isDirty : function()
206   - {
207   - if (this.dirty)
208   - return true;
209   -
210   - if (this.get('page-layout-object') != null)
211   - if (this.get('page-layout-object').dirty)
212   - return true;
213   -
214   - var d = false;
215   - this.panels().each(function (panel, index) {
216   - if (panel.isDirty())
217   - d = true;
218   - });
219   - return d;
220   - },
221   -
222   - getJsonValues : function()
223   - {
224   - var tabValues = new Object();
225   -
226   - tabValues['id'] = this.get('id');
227   - tabValues['tab-name'] = this.get('tab-name');
228   - tabValues['tree-full-view'] = this.get('tree-full-view');
229   - tabValues['multi-plot-linked'] = this.get('multi-plot-linked');
230   - tabValues['page-node-state'] = this.get('page-node-state');
231   - tabValues['panels-node-state'] = this.get('panels-node-state');
232   - tabValues['page-title-text'] = this.get('page-title-text');
233   - tabValues['page-title-color'] = this.get('page-title-color');
234   - tabValues['page-title-position'] = this.get('page-title-position');
235   - tabValues['page-title-alignment'] = this.get('page-title-alignment');
236   - tabValues['page-title-font-activated'] = this.get('page-title-font-activated');
237   - tabValues['page-title-font-name'] = this.get('page-title-font-name');
238   - tabValues['page-title-font-size'] = this.get('page-title-font-size');
239   - tabValues['page-title-font-bold'] = this.get('page-title-font-bold');
240   - tabValues['page-title-font-italic'] = this.get('page-title-font-italic');
241   - tabValues['page-margins-activated'] = this.get('page-margins-activated');
242   - tabValues['page-margin-x'] = this.get('page-margin-x');
243   - tabValues['page-margin-y'] = this.get('page-margin-y');
244   - tabValues['page-mode'] = this.get('page-mode');
245   - tabValues['page-orientation'] = this.get('page-orientation');
246   - tabValues['page-dimension'] = this.get('page-dimension');
247   - tabValues['page-superpose-mode'] = this.get('page-superpose-mode');
248   - tabValues['page-font-activated'] = this.get('page-font-activated');
249   - tabValues['page-font-name'] = this.get('page-font-name');
250   - tabValues['page-font-size'] = this.get('page-font-size');
251   - tabValues['page-font-bold'] = this.get('page-font-bold');
252   - tabValues['page-font-italic'] = this.get('page-font-italic');
253   -
254   - tabValues['timesrc'] = this.get('timesrc');
255   - // if there's at least one timeTable name into 'timeTables' collection
256   - if (this.get('timesrc') == amdaModel.AmdaTimeObject.inputTimeSrc[0] && this.get('timeTables') && this.get('timeTables').length){
257   - // get complete timeTables collection
258   - var timeTables = this.get('timeTables');
259   - // init an empty array for timeTables
260   - tabValues['timeTables'] = [];
261   - // for each interval record
262   - Ext.Array.each(timeTables, function(item, index, all){
263   - if (!item.$className) {
264   - tabValues['timeTables'][index] = {timeTableName : item.timeTableName, id : item.id};
265   - }
266   - // get Json simplified value
267   - else {
268   - tabValues['timeTables'][index] = item.getJsonValues();
269   - }
270   - });
271   - } else {
272   - tabValues['startDate'] = this.get('startDate');
273   - tabValues['stopDate'] = this.get('stopDate');
274   - tabValues['durationDay'] = this.get('durationDay');
275   - tabValues['durationHour'] = this.get('durationHour');
276   - tabValues['durationMin'] = this.get('durationMin');
277   - tabValues['durationSec'] = this.get('durationSec');
278   - }
279   -
280   - tabValues['page-layout-type'] = this.get('page-layout-type');
281   - if (this.get('page-layout-object') != null)
282   - tabValues['page-layout-object'] = this.get('page-layout-object').getJsonValues();
283   -
284   - tabValues['panels'] = [];
285   -
286   - this.panels().each(function (panel, index) {
287   - tabValues['panels'][index] = panel.getJsonValues();
288   - });
289   -
290   - tabValues['last-panel-id'] = this.get('last-panel-id');
291   -
292   - return tabValues;
293   - }
294   -});
js/app/models/PlotTabNode.js deleted
... ... @@ -1,164 +0,0 @@
1   -/**
2   - * Project : AMDA-NG4
3   - * Name : PlotTabNode.js
4   - * @class amdaModel.PlotTabNode
5   - * @extends amdaModel.ExecutableNode
6   - * @brief Basic Model of Node corresponding to a tab of a plot request
7   - * @author Benjamin Renard
8   - */
9   -
10   -Ext.define('amdaModel.PlotTabNode', {
11   - extend: 'amdaModel.ExecutableNode',
12   -
13   - fields : [
14   - {name : 'tabid', type:'string', defaultValue:'', persist: false}
15   - ],
16   -
17   - statics: {
18   - nodeType: 'plottab'
19   - },
20   -
21   - constructor : function(config){
22   - this.callParent(arguments);
23   - this.set('moduleId',myDesktopApp.dynamicModules.plot.id);
24   - //this.set('objectDataModel','amdaPlotObj.PlotRequestObject');
25   - this.set('nodeType',this.self.nodeType);
26   - this.set('leaf',true);
27   - this.set('iconCls','icon-plot-page');
28   - },
29   -
30   - allMenuItems : function() {
31   - var menuItems =
32   - [
33   - {
34   - fnId : 'ptab-openTab',
35   - text : 'Open in new Plot Request'
36   - }, {
37   - fnId : 'ptab-insertTab',
38   - text : 'Insert in current Plot Request'
39   - }, {
40   - fnId : 'ptab-renameTab',
41   - text : 'Rename Plot Tab'
42   - }];
43   -
44   - return menuItems;
45   - },
46   -
47   - allMenuMultiItems : function() {
48   - var menuMulti = [
49   - ];
50   - return menuMulti;
51   - },
52   -
53   - getAllContextMenuItems: function(){
54   - return this.allMenuItems();
55   - },
56   -
57   - getMultiContextMenuItems: function(){
58   - return this.allMenuMultiItems();
59   - },
60   -
61   - onMenuItemClick : function(menu,item,event) {
62   -
63   - var fnId = Ext.util.Format.substr(item.fnId, 5, item.fnId.length);
64   -
65   - switch (fnId) {
66   -
67   - case 'openTab':
68   - this.insertPlotTabRequest(true);
69   - break;
70   -
71   - case 'insertTab':
72   - this.insertPlotTabRequest(false);
73   - break;
74   -
75   - case 'renameTab':
76   - this.renameTab();
77   - break;
78   - default:
79   - break;
80   - }
81   - },
82   -
83   - insertPlotTabRequest : function(inNewRequest) {
84   - var me = this;
85   - amdaModel.InteractiveNode.preloadNodes(this.parentNode.getRootNode(), function() {
86   - AmdaAction.getObject(me.parentNode.get('id'), me.parentNode.get('nodeType'), function (result,remoteEvent) {
87   - var paramObj = Ext.create(me.parentNode.get('objectDataModel'), result);
88   - var tabData = null;
89   - paramObj.tabs().each(function(tab) {
90   - if (tab.get('id') == me.get('tabid')) {
91   - tabData = tab.getJsonValues();
92   - }
93   - });
94   - if (tabData != null) {
95   - if (inNewRequest) {
96   - tabData['id'] = 1;
97   - paramObj.set('id','');
98   - paramObj.set('name', '');
99   - paramObj.set('folderId', '');
100   - paramObj.set('active-tab-id', 1);
101   - paramObj.set('last-tab-id', 1);
102   - paramObj.set('last-plotted-tab', 1);
103   - paramObj.loadTabs([tabData]);
104   - myDesktopApp.getLoadedModule(me.get('moduleId'), true, function (module) {
105   - module.setContextNode(me.parentNode.getRootNode());
106   - module.createWindow(function () {
107   - var uiContent = module.getUiContent();
108   - if (uiContent != null) {
109   - uiContent.resetProcess(paramObj.getJsonValues());
110   - }
111   - });
112   - });
113   - }
114   - else {
115   - myDesktopApp.getLoadedModule(me.get('moduleId'), true, function (module) {
116   - module.createWindow(function () {
117   - var uiContent = module.getUiContent();
118   - if (uiContent != null) {
119   - var tabObj = new amdaPlotObj.PlotTabObject(tabData);
120   - uiContent.insertPlotTab(tabData);
121   - }
122   - });
123   - });
124   - }
125   - }
126   - }, me);
127   - });
128   - },
129   -
130   - editPlotTab : function() {
131   - var me = this;
132   - this.parentNode.editLeaf(function () {
133   - myDesktopApp.getLoadedModule(me.get('moduleId'), true, function (module) {
134   - var uiContent = module.getUiContent();
135   - if (uiContent != null) {
136   - uiContent.forceActiveTab(me.get('tabid'));
137   - }
138   - });
139   - });
140   - },
141   -
142   - renameTab: function() {
143   - if (this.myGetOwnerTree()) {
144   - var item = this.myGetOwnerTree().getSelectionModel().selected.items[0];
145   - this.myGetOwnerTree().fireEvent('edition', this.myGetOwnerTree().view, item);
146   - }
147   - },
148   -
149   - rename: function(value,callBackFn) {
150   - var me = this;
151   - var dataToSend = {id : this.get('tabid'), old_name: this.modified.text, name: value, parent : this.data.parentId, leaf: this.isLeaf(), nodeType: this.get('nodeType')};
152   - AmdaAction.renameObject(dataToSend, function (result) {
153   - callBackFn(result);
154   - myDesktopApp.getLoadedModule(me.get('moduleId'), true, function (module) {
155   - var uiContent = module.getUiContent();
156   - if (uiContent != null) {
157   - if ((module.linkedNode != null) && (module.linkedNode.get('id') == dataToSend.parent)) {
158   - uiContent.updatePlotTabName(dataToSend.id, dataToSend.name);
159   - }
160   - }
161   - });
162   - });
163   - },
164   -});
js/app/views/ExplorerUI.js
... ... @@ -102,7 +102,6 @@ Ext.define(&#39;amdaUI.ExplorerUI&#39;, {
102 102 ITEM_KIND_LEAF : 'leaf',
103 103 ITEM_KIND_DIRE : 'dire',
104 104 ITEM_KIND_PARA : 'para',
105   - ITEM_KIND_PTAB : 'ptab', //plot tab
106 105 ITEM_KIND_MISS : 'miss'
107 106 },
108 107  
... ... @@ -354,7 +353,6 @@ Ext.define(&#39;amdaUI.ExplorerUI&#39;, {
354 353 case 'remoteParam' :
355 354 case 'remoteSimuParam' :
356 355 case 'myData' :
357   - case 'plottab' :
358 356 return false;
359 357 default :
360 358 if (draggedRecord.data.id == targetNode.data.nodeType+'-treeRootNode')
... ... @@ -577,7 +575,7 @@ Ext.define(&#39;amdaUI.ExplorerUI&#39;, {
577 575 });
578 576 }
579 577  
580   - if (record.isLeaf() || record.data.isParameter || (record.data.tabs && (record.data.tabs.length > 0)))
  578 + if (record.isLeaf() || record.data.isParameter)
581 579 switch (record.get('nodeType'))
582 580 {
583 581 case 'myData' :
... ... @@ -591,9 +589,6 @@ Ext.define(&#39;amdaUI.ExplorerUI&#39;, {
591 589 case 'condition' :
592 590 record.editLeaf();
593 591 break;
594   - case 'plottab' :
595   - record.editPlotTab();
596   - break;
597 592 case 'localParam' :
598 593 case 'remoteParam':
599 594 case 'remoteSimuParam':
... ... @@ -1029,7 +1024,7 @@ Ext.define( &#39;MyTreeEditor&#39;, {
1029 1024 event.record.commit();
1030 1025 var rec = event.record.data;
1031 1026 // in case of directory
1032   - if (!rec.leaf && (rec.nodeType != 'plottab')){
  1027 + if (!rec.leaf){
1033 1028 // set folder's ID returned by server
1034 1029 rec.id = result.id;
1035 1030 }
... ...
js/app/views/IntervalUI.js
... ... @@ -125,6 +125,9 @@ Ext.define(&#39;amdaUI.IntervalUI&#39;, {
125 125 if (stop != null && start != null) {
126 126 if ( stop <= start ) {
127 127 form.findField('stopDate').markInvalid('Stop Time must be after Start Time');
  128 + } else {
  129 + if (!form.findField('stopDate').isValid())
  130 + form.findField('stopDate').clearInvalid();
128 131 }
129 132 // compute offset
130 133 var zoneOffset = stop.getTimezoneOffset() - start.getTimezoneOffset();
... ... @@ -159,6 +162,21 @@ Ext.define(&#39;amdaUI.IntervalUI&#39;, {
159 162 );
160 163 },
161 164  
  165 + isValid: function() {
  166 + var form = this.findParentByType('form').getForm();
  167 + var startField = form.findField('startDate');
  168 + var stopField = form.findField('stopDate');
  169 + if (!startField.isValid() || !stopField.isValid())
  170 + return false;
  171 + var start = this.getStartTime();
  172 + var stop = this.getStopTime();
  173 + if ( stop <= start ) {
  174 + form.findField('stopDate').markInvalid('Stop Time must be after Start Time');
  175 + return false;
  176 + }
  177 + return true;
  178 + },
  179 +
162 180 updateStop: function() {
163 181 var form = this.findParentByType('form').getForm();
164 182 var start = form.findField('startDate').getValue();
... ...
js/app/views/PlotComponents/PlotElementPanel.js
... ... @@ -10,6 +10,7 @@
10 10  
11 11 Ext.define('amdaPlotComp.PlotElementPanel', {
12 12 extend: 'Ext.form.Panel',
  13 +
13 14  
14 15 elementFormsManager : new Ext.AbstractManager(),
15 16  
... ...
js/app/views/PlotComponents/PlotExtendShiftPlug.js
... ... @@ -21,7 +21,7 @@ Ext.define(&#39;amdaPlotComp.PlotExtendShiftPlug&#39;, {
21 21 id: 'plot-extendshift-plug',
22 22 win : null,
23 23 form : null,
24   - tabId : '',
  24 + interactiveId : '',
25 25  
26 26 constructor: function(config) {
27 27 Ext.apply(this, config);
... ... @@ -39,7 +39,7 @@ Ext.define(&#39;amdaPlotComp.PlotExtendShiftPlug&#39;, {
39 39 /**
40 40 * creation of the window
41 41 */
42   - show : function(tabId) {
  42 + show : function(interactiveId) {
43 43 if (!this.win)
44 44 {
45 45 this.win = new Ext.Window({
... ... @@ -77,7 +77,7 @@ Ext.define(&#39;amdaPlotComp.PlotExtendShiftPlug&#39;, {
77 77 Ext.PluginManager.register(this);
78 78 }
79 79  
80   - this.tabId = tabId;
  80 + this.interactiveId = interactiveId;
81 81 this.win.show();
82 82 this.win.setPosition(0,0);
83 83 },
... ... @@ -111,7 +111,7 @@ Ext.define(&#39;amdaPlotComp.PlotExtendShiftPlug&#39;, {
111 111 var durationUnitField = this.form.getForm().findField('durationUnit');
112 112 var duration = this.toSec(durationField.getValue(), durationUnitField.getValue());
113 113 if (duration) {
114   - this.hostCmp.callInteractivePlot({'action' : actionType, 'tabId' : this.tabId, 'duration' : duration});
  114 + this.hostCmp.callInteractivePlot({'action' : actionType, 'interactiveId' : this.interactiveId, 'duration' : duration});
115 115 }
116 116 else
117 117 myDesktopApp.errorMsg('No duration defined');
... ... @@ -190,4 +190,4 @@ Ext.define(&#39;amdaPlotComp.PlotExtendShiftPlug&#39;, {
190 190 });
191 191 return this.form;
192 192 }
193   -});
194 193 \ No newline at end of file
  194 +});
... ...
js/app/views/PlotComponents/PlotPreviewUI.js
... ... @@ -80,7 +80,7 @@ Ext.define(&#39;amdaPlotComp.PlotPreviewUI&#39;, {
80 80 var me = this;
81 81  
82 82 this.crtContext = configResult.context;
83   - this.tabId = configResult.tabId;
  83 + this.interactiveId = configResult.interactiveId;
84 84  
85 85 this.sliderPage = new Ext.slider.Single({
86 86 width: 130,
... ... @@ -136,7 +136,7 @@ Ext.define(&#39;amdaPlotComp.PlotPreviewUI&#39;, {
136 136 me.hiddenForm.getForm().submit({
137 137 params: {
138 138 sessionId: sessionID,
139   - tabId : me.tabId,
  139 + interactiveId : me.interactiveId,
140 140 preview: true
141 141 },
142 142 success: function(form, action) {},
... ...
js/app/views/PlotComponents/PlotStandardForm.js
... ... @@ -87,7 +87,6 @@ Ext.define(&#39;amdaPlotComp.PlotStandardForm&#39;, {
87 87 allowBlank = (typeof allowBlank !== 'undefined') ? allowBlank : false;
88 88  
89 89 return {
90   - id:name,
91 90 xtype: 'numberfield',
92 91 name: name,
93 92 fieldLabel: label,
... ... @@ -112,7 +111,6 @@ Ext.define(&#39;amdaPlotComp.PlotStandardForm&#39;, {
112 111 allowBlank = (typeof allowBlank !== 'undefined') ? allowBlank : false;
113 112  
114 113 return {
115   - id:name,
116 114 xtype: 'textfield',
117 115 name: name,
118 116 fieldLabel: label,
... ...
js/app/views/PlotComponents/PlotTabContent.js
... ... @@ -9,86 +9,242 @@
9 9 */
10 10  
11 11 Ext.define('amdaPlotComp.PlotTabContent', {
12   - extend: 'Ext.form.Panel',
13   -
14   - requires: [
15   - 'amdaUI.TimeSelectorUI',
16   - 'amdaPlotComp.PlotTree'
  12 + extend: 'Ext.form.Panel',
  13 +
  14 + requires: [
  15 + 'amdaUI.TimeSelectorUI',
  16 + 'amdaPlotComp.PlotTree',
  17 + 'amdaPlotComp.PlotOutputForm',
  18 + 'amdaPlotComp.PlotElementPanel'
17 19 ],
18 20  
19   - treePlot: null,
20   -
21   - //Link to the Plot Element Panel
22   - plotElementPanel: null,
23   -
24   - //linkk to the Plot Tab Panel
25   - plotTabPanel : null,
26   -
27   - //Link to the time selctor
28   - timeSelector : null,
29   -
30   - //Tab Object
31   - object: null,
  21 + //Link to the Plot Node
  22 + plotNode: null,
  23 +
  24 + //Save initial request data to have the possibility to reject all modifications
  25 + initialObjectData: null,
  26 +
  27 + timeSelector: null,
  28 + plotTree: null,
  29 + plotElement: null,
  30 + plotOutput: null,
  31 +
  32 + tabIndex: 0,
  33 + plotTabPanel: null,
32 34  
33 35 constructor: function(config) {
34 36 this.init(config);
35 37 this.callParent(arguments);
36   - },
37   -
38   - setTabObject : function(object) {
39   - this.object = object;
40   - this.treePlot.buildTree(this.object);
41   - this.timeSelector.intervalSel.setInterval(this.object.get('startDate'), this.object.get('stopDate'));
42   - this.addTTs(this.object.get('timeTables'));
43   - },
44   -
45   - addTTs : function(TTarray) {
46   - // set TTTab
47   - this.timeSelector.setTTTab(TTarray);
48   - },
49   -
50   - updateLinkedToMultiPlotMode : function (isLinkedToMultiPlotMode) {
51   - this.timeSelector.setVisible(!isLinkedToMultiPlotMode);
52   - this.plotTabPanel.updateLinkedToMultiPlotMode(isLinkedToMultiPlotMode);
53   - },
54   -
55   - updateTimeObject : function() {
56   - var timeSource = this.timeSelector.getActiveTimeSource();
57   - var tabForm = this.getForm();
58   - tabForm.updateRecord(this.object);
59   - this.object.set('timesrc', timeSource);
60   - if (timeSource === amdaModel.AmdaTimeObject.inputTimeSrc[0])
61   - this.object.set('timeTables',this.timeSelector.TTGrid.getStore().data.items);
62   - },
  38 + },
  39 +
  40 + setTime : function(startDate, stopDate) {
  41 + this.timeSelector.intervalSel.setInterval(startDate, stopDate);
  42 +
  43 + },
63 44  
64   - init : function(config) {
65   - var me = this;
66   -
67   - this.plotElementPanel = config.plotElementPanel;
68   - this.plotTabPanel = config.plotTabPanel;
69   -
70   - this.timeSelector = new amdaUI.TimeSelectorUI( { id: 'plotTimeSelectorTab' + config.tabId, border : false, flex: 3, collapsible: true, collapseDirection : 'bottom', hidden: true} );
71   - this.treePlot = new amdaPlotComp.PlotTree({flex: 5.6, plotElementPanel: this.plotElementPanel, plotTabContent: this});
72   -
73   - var myConf = {
74   - bodyStyle: { background : '#dfe8f6' },
75   - border : false,
76   - defaults: {
77   - border: false
78   - },
79   - layout: {
80   - type: 'vbox',
81   - pack: 'start',
82   - align: 'stretch'
83   - },
84   - items: [
85   - this.treePlot,
86   - this.timeSelector
87   - ]
88   - };
  45 + updateTimeObject : function() {
  46 + var timeSource = this.timeSelector.getActiveTimeSource();
  47 + var tabForm = this.getForm();
  48 + tabForm.updateRecord(this.plotNode.get('object'));
  49 + this.plotNode.get('object').set('timesrc', timeSource);
  50 + if (timeSource === amdaModel.AmdaTimeObject.inputTimeSrc[0])
  51 + this.plotNode.get('object').set('timeTables',this.timeSelector.TTGrid.getStore().data.items);
  52 + },
  53 +
  54 + doPlot : function() {
  55 + this.plotNode.get('object').set('tab-index', this.tabIndex);
  56 + this.plotNode.get('object').set('tab-title', this.getPlotTitle());
  57 + this.plotNode.execute();
  58 + },
  59 +
  60 + getPlotTitle: function() {
  61 + return (this.plotNode.get('text') != '') ? this.plotNode.get('text') : 'Plot '+(this.tabIndex + 1);
  62 + },
  63 +
  64 + savePlot : function() {
  65 + var me = this;
  66 +
  67 + var object = this.plotNode.get('object');
  68 + if (!object)
  69 + return;
  70 +
  71 + if ((object.get('id') != '') && (this.plotNode.get('text') == object.get('name'))) {
  72 + //update existing request
  73 + this.updateTimeObject();
  74 + this.plotNode.update({plot: true, callback: function() {
  75 + me.setPlotNode(me.plotNode); //to update initial request data
  76 + me.plotTabPanel.updatePlotTabs();
  77 + }});
  78 + return;
  79 + }
  80 +
  81 + //save new request
  82 + this.plotNode.isValidName(object.get('name'), function (res) {
  83 + if (!res) {
  84 + myDesktopApp.errorMsg('Error during object validation');
  85 + return;
  86 + }
  87 + if (!res.valid) {
  88 + if (res.error) {
  89 + if (res.error.search('subtree') != -1) {
  90 + Ext.Msg.show( { title : 'Warning',
  91 + msg: res.error + '<br/>Do you want to overwrite it?',
  92 + width: 300,
  93 + buttons: Ext.Msg.OKCANCEL,
  94 + icon: Ext.Msg.WARNING,
  95 + fn : function(btn) {
  96 + if (btn == 'cancel') return;
  97 + me.saveProcess(true);
  98 + },
  99 + scope : me
  100 + });
  101 + }
  102 + else {
  103 + myDesktopApp.errorMsg(res.error);
  104 + }
  105 + }
  106 + else {
  107 + myDesktopApp.errorMsg('Invalid object name');
  108 + }
  109 + return;
  110 + }
  111 + me.saveProcess(false);
  112 + });
  113 + },
  114 +
  115 + saveProcess : function(toRename) {
  116 + var me = this;
  117 + if (toRename) {
  118 + this.updateTimeObject();
  119 + this.plotNode.update({plot: true, callback: function() {
  120 + me.setPlotNode(me.plotNode); //to update initial request data
  121 + me.plotTabPanel.updatePlotTabs();
  122 + }});
  123 + }
  124 + else {
  125 + if (this.plotNode.get('object').get('id') != '') {
  126 + //Duplicate request
  127 + var plotModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.plot.id);
  128 + if (!plotModule)
  129 + return;
  130 + var newPlotNode = plotModule.linkedNode.get('object').duplicatePlot(this.plotNode);
  131 + if (newPlotNode) {
  132 + //Reject modifications in old plot node
  133 + this.plotNode.reject();
  134 + this.plotNode.set('object', Ext.create('amdaPlotObj.PlotRequestObject', this.initialObjectData));
  135 + //Set new plot node
  136 + this.setPlotNode(newPlotNode);
  137 + }
  138 + }
  139 + this.updateTimeObject();
  140 + this.plotNode.create({callback: function() {
  141 + me.plotNode.commit();
  142 + me.setPlotNode(me.plotNode); //to update initial request data
  143 + me.plotTabPanel.updatePlotTabs();
  144 + me.updateUI();
  145 + }});
  146 + }
  147 + },
  148 +
  149 + getDataProcess : function() {
  150 + var downObject = amdaModel.DownloadNode.decodeObject(this.plotNode.get('object'));
  151 + amdaModel.DownloadNode.set('object',Ext.create('amdaModel.Download',downObject));
  152 + amdaModel.DownloadNode.editInModule();
  153 + },
  154 +
  155 + isValidRequest : function(acceptEmptyTTList = true) {
  156 + this.updateTimeObject();
  157 + if (!this.timeSelector.isValid(acceptEmptyTTList)) {
  158 + myDesktopApp.errorMsg('Error in Time definition');
  159 + return false;
  160 + }
  161 + return true;
  162 + },
  163 +
  164 + updateUI : function() {
  165 + this.plotOutput.setObject(this.plotNode.get('object'));
  166 + this.timeSelector.intervalSel.setInterval(this.plotNode.get('object').get('startDate'), this.plotNode.get('object').get('stopDate'));
  167 + this.timeSelector.intervalSel.updateStop();
  168 + this.timeSelector.setTTTab(this.plotNode.get('object').get('timeTables'));
  169 + this.timeSelector.timeSrc.setActiveTab(this.plotNode.get('object').get('timesrc'));
  170 + this.treePlot.buildTree(this.plotNode.get('object'));
  171 + },
  172 +
  173 + setPlotNode : function(plotNode) {
  174 + this.initialObjectData = plotNode.get('object').getJsonValues();
  175 + this.plotNode = plotNode;
  176 + },
  177 +
  178 + init : function(config) {
  179 + this.setPlotNode(config.plotNode);
  180 + this.tabIndex = config.tabIndex;
  181 + this.plotTabPanel = config.plotTabPanel;
  182 +
  183 + this.timeSelector = new amdaUI.TimeSelectorUI( { id: Ext.id()/*'plotTimeSelectorTab' + this.plotNode.id*/, border : false, flex: 6, collapsible: true, collapseDirection : 'bottom'} );
  184 + this.plotElement = new amdaPlotComp.PlotElementPanel({flex: 11});
  185 + this.treePlot = new amdaPlotComp.PlotTree({flex: 11, plotElementPanel: this.plotElement});
  186 + this.plotOutput = new amdaPlotComp.PlotOutputForm({flex: 6, collapseDirection : 'bottom', collapsible : true });
  187 +
  188 + var treePanel = new Ext.form.Panel({
  189 + flex: 1,
  190 + layout: {
  191 + type: 'vbox',
  192 + pack: 'start',
  193 + align: 'stretch'
  194 + },
  195 + bodyStyle: { background : '#dfe8f6' },
  196 + defaults: {
  197 + border: false
  198 + },
  199 + items: [
  200 + this.treePlot,
  201 + this.timeSelector
  202 + ]
  203 + });
  204 +
  205 + var optionsPanel = new Ext.form.Panel({
  206 + flex: 1,
  207 + layout: {
  208 + type: 'vbox',
  209 + pack: 'start',
  210 + align: 'stretch'
  211 + },
  212 + bodyStyle: { background : '#dfe8f6' },
  213 + defaults: {
  214 + border: false
  215 + },
  216 + items: [
  217 + this.plotElement,
  218 + this.plotOutput
  219 + ]
  220 + });
  221 +
89 222  
90   - Ext.apply (this , Ext.apply (arguments, myConf));
  223 + var myConf = {
  224 + bodyStyle: { background : '#dfe8f6' },
  225 + border : false,
  226 + defaults: {
  227 + border: false
  228 + },
  229 + layout: {
  230 + type: 'hbox',
  231 + pack: 'start',
  232 + align: 'stretch'
  233 + },
  234 + items: [
  235 + treePanel,
  236 + optionsPanel
  237 + ],
  238 + listeners: {
  239 + afterrender: function(comp, eOpts) {
  240 + this.updateUI();
  241 + },
  242 + scope: this
  243 + }
  244 + };
  245 +
  246 + Ext.apply (this , Ext.apply (arguments, myConf));
91 247  
92 248  
93   - }
94   -});
95 249 \ No newline at end of file
  250 + }
  251 +});
... ...
js/app/views/PlotComponents/PlotTabPanel.js
... ... @@ -9,206 +9,178 @@
9 9 */
10 10  
11 11 Ext.define('amdaPlotComp.PlotTabPanel', {
12   - extend: 'Ext.tab.Panel',
  12 + extend: 'Ext.tab.Panel',
13 13  
14   - requires: [
15   - 'amdaPlotComp.PlotTabContent'
16   - ],
  14 + requires: [
  15 + 'amdaPlotComp.PlotTabContent'
  16 + ],
17 17  
18   - //Link to the Plot Element Panel
19   - plotElementPanel: null,
20   -
21 18 //Link to the Plot UI
22 19 plotUI : null,
23 20  
24   - //Request object
25   - object: null,
  21 + //Multiplot object
  22 + multiplot_object: null,
  23 +
  24 + tabbar_destroy : false,
26 25  
27   - constructor: function(config) {
28   - this.init(config);
29   - this.callParent(arguments);
30   - },
  26 + constructor: function(config) {
  27 + this.init(config);
  28 + this.callParent(arguments);
  29 + },
31 30  
32   - setRequestObject: function(object)
33   - {
34   - var me = this;
35   - this.removeAll();
36   - this.object = object;
  31 + setMultiplotObject: function(multiplot_object) {
  32 + var me = this;
  33 + this.removeAll();
  34 + this.multiplot_object = multiplot_object;
37 35  
38   - var haveSelectedTab = false;
39   - this.object.tabs().each(function (rec, index) {
40   - if (rec.get('id') == me.object.get('active-tab-id')) {
41   - haveSelectedTab = true;
42   - }
43   - });
  36 + this.multiplot_object.plots().each(function (rec, index) {
  37 + this.addPlotNode(rec, index == 0);
  38 + }, this);
  39 + },
44 40  
45   - this.object.tabs().each(function (rec, index) {
46   - var isSelectedTab = haveSelectedTab ? (rec.get('id') == me.object.get('active-tab-id')) : (index == 0);
47   - this.addPlotTab(rec, isSelectedTab);
48   - }, this);
49   - },
  41 + reloadPlot : function(plotNode) {
  42 + for (i = 0; i < this.items.getCount(); ++i)
  43 + {
  44 + var tabItem = this.items.getAt(i);
  45 + var tabContent = tabItem.items.getAt(0);
  46 + if (plotNode == tabContent.plotNode) {
  47 + tabContent.updateUI();
  48 + }
  49 + }
  50 + },
50 51  
51   - addPlotTab: function(tabObject, selectTab)
52   - {
53   - var tabNumber = this.getTabBar().items.getCount();
54   - var tabContent = new amdaPlotComp.PlotTabContent({plotElementPanel: this.plotElementPanel, plotTabPanel : this, tabId : tabObject.get('id')});
55   - tabContent.setTabObject(tabObject);
56   - var me = this;
57   - var tabComp = this.add({
58   - title: (tabObject.get('tab-name') != '') ? tabObject.get('tab-name') : 'Plot '+tabNumber,
59   - closable: true,
60   - layout: 'fit',
61   - bodyStyle: 'background: none',
62   - defaults: {
63   - border: false
64   - },
65   - items: [
66   - tabContent
67   - ],
68   - listeners : {
69   - scope : this,
70   - beforeclose: function( tab, eOpts ) {
71   - if (this.items.getCount() == 1)
72   - {
73   - myDesktopApp.warningMsg('You need to keep at least one plot definition');
74   - return false;
75   - }
76   - return true;
77   - },
78   - close: function( tab, eOpts ) {
79   - if (tab.items.getAt(0).object)
80   - this.object.removeTabById(tab.items.getAt(0).object.get('id'));
81   - },
82   - destroy: function(tab, eOpts) {
83   -
84   - this.updatePlotTabs();
85   - },
86   - afterrender: function(tab, e0pts) {
87   - if (!tab.tab.el) {
88   - return;
89   - }
90   - tab.tab.el.on('contextmenu', function(e, t, eOpts) {
91   - var menu = new Ext.menu.Menu({
92   - items: [
93   - {
94   - text: 'Rename',
95   - handler: function() {
96   - Ext.Msg.prompt('Rename', 'Please enter new plot tab name:', function(btn, text){
97   - if (btn == 'ok'){
98   - tabObject.set('tab-name',text);
99   - me.updatePlotTabs();
100   - }
101   - }, me);
102   - }
103   - }
104   - ]
105   - });
106   - var position = e.getXY();
107   - e.stopEvent();
108   - menu.showAt(position);
109   - },this);
110   - }
111   - }
112   - });
  52 + addPlotNode: function(plotNode, selectTab)
  53 + {
  54 + for (i = 0; i < this.items.getCount(); ++i)
  55 + {
  56 + var tabItem = this.items.getAt(i);
  57 + var tabContent = tabItem.items.getAt(0);
  58 + if (plotNode == tabContent.plotNode) {
  59 + //Already opened => select tab
  60 + this.setActiveTab(tabItem);
  61 + return;
  62 + }
  63 + }
  64 +
  65 + var tabNumber = this.getTabBar().items.getCount();
  66 + var tabContent = new amdaPlotComp.PlotTabContent({plotNode: plotNode, tabIndex: tabNumber-1, plotTabPanel: this});
  67 + var me = this;
  68 + var tabComp = this.add({
  69 + title: tabContent.getPlotTitle(),
  70 + closable: true,
  71 + layout: 'fit',
  72 + bodyStyle: 'background: none',
  73 + defaults: {
  74 + border: false
  75 + },
  76 + items: [
  77 + tabContent
  78 + ],
  79 + listeners : {
  80 + scope : this,
  81 + beforeclose: function( tab, eOpts ) {
  82 + if (this.items.getCount() == 1)
  83 + {
  84 + myDesktopApp.warningMsg('You need to keep at least one plot definition');
  85 + return false;
  86 + }
  87 + return true;
  88 + },
  89 + close: function( tab, eOpts ) {
  90 + if (tab.items.getAt(0).plotNode) {
  91 + this.multiplot_object.removePlotByInternalId(tab.items.getAt(0).plotNode.internalId);
  92 + }
  93 + },
  94 + destroy: function(tab, eOpts) {
  95 + if (!this.tabbar_destroy)
  96 + this.updatePlotTabs();
  97 + }
  98 + }
  99 + });
113 100  
114   - if (selectTab)
115   - this.setActiveTab(tabComp);
  101 + if (selectTab)
  102 + this.setActiveTab(tabComp);
116 103  
117   - return tabContent;
118   - },
  104 + return tabContent;
  105 + },
119 106  
120   - updatePlotTabs: function()
121   - {
122   - var me = this;
123   - var haveSelectedTab = false;
124   - this.object.tabs().each(function (rec, index) {
125   - if (rec.get('id') == me.object.get('active-tab-id')) {
126   - haveSelectedTab = true;
127   - }
128   - });
  107 + updatePlotTabs: function()
  108 + {
  109 + for (i = 0; i < this.items.getCount(); ++i)
  110 + {
  111 + var tabItem = this.items.getAt(i);
  112 + var tabContent = tabItem.items.getAt(0);
  113 + tabContent.tabIndex = i;
  114 + var plotNode = tabContent.plotNode;
  115 + var title = tabContent.getPlotTitle();
  116 + tabItem.setTitle(title);
  117 + if (!this.getActiveTab())
  118 + this.setActiveTab(tabItem);
  119 + }
  120 + },
129 121  
130   - var i = 0;
131   - for (i = 0; i < this.items.getCount(); ++i)
132   - {
133   - var tabItem = this.items.getAt(i);
134   - var tabContent = tabItem.items.getAt(0);
135   - var tabObj = this.object.tabs().getById(tabContent.tabId);
136   - if (!tabObj) {
137   - continue;
138   - }
139   - if (!haveSelectedTab) {
140   - //Set first tab as the selected one
141   - this.setActiveTab(tabItem);
142   - this.object.set('active-tab-id', tabObj.get('id'));
143   - haveSelectedTab = true;
144   - }
145   - var tabNumber = i+1;
146   - tabItem.setTitle((tabObj.get('tab-name') != '') ? tabObj.get('tab-name') : 'Plot '+tabNumber);
147   - tabContent.setTabObject(tabObj);
148   - }
149   - },
150   -
151   - updateLinkedToMultiPlotMode : function(isLinkedToMultiPlotMode) {
152   - this.plotUI.updateLinkedToMultiPlotMode(isLinkedToMultiPlotMode);
153   - },
154   -
155   - updateTimeObject : function() {
156   - for (i = 0; i < this.items.getCount(); ++i)
157   - {
158   - this.items.getAt(i).items.getAt(0).updateTimeObject();
159   - }
160   - },
  122 + updateRequestName: function(renamedNode)
  123 + {
  124 + for (i = 0; i < this.items.getCount(); ++i)
  125 + {
  126 + var tabItem = this.items.getAt(i);
  127 + var tabContent = tabItem.items.getAt(0);
  128 + var plotNode = tabContent.plotNode;
  129 + if (plotNode == renamedNode) {
  130 + plotNode.get('object').set('name', renamedNode.get('text'));
  131 + tabContent.updateUI();
  132 + }
  133 + }
  134 + },
  135 +
  136 + getCurrentPlotTabContent : function() {
  137 + if (this.getActiveTab())
  138 + return this.getActiveTab().child();
  139 + return null;
  140 + },
161 141  
162   - getTreeFromPlotTab: function(plotTab)
163   - {
164   - return plotTab.child().treePlot;
165   - },
  142 + updateTimeObjects : function() {
  143 + for (i = 0; i < this.items.getCount(); ++i)
  144 + {
  145 + this.items.getAt(i).items.getAt(0).updateTimeObject();
  146 + }
  147 + },
166 148  
167   - getSelectedTabId: function()
168   - {
169   - if (this.getActiveTab())
170   - return this.getActiveTab().child().tabId;
171   - return 0;
172   - },
  149 + getTreeFromPlotTab: function(plotTab)
  150 + {
  151 + return plotTab.child().treePlot;
  152 + },
173 153  
174   - init : function(config) {
175   - var me = this;
176   -
177   - this.plotElementPanel = config.plotElementPanel;
178   - this.plotUI = config.plotUI;
179   -
180   - var myConf = {
181   - plain: true,
182   - bodyStyle: { background : '#dfe8f6' },
183   - border : false,
184   - defaults: {
185   - border: false
186   - },
187   - tabBar:{
188   - items:[
189   - {
190   - text:'+',
191   - closable: false,
192   - handler:function(btn,e){
193   - var tabContent = me.addPlotTab(me.object.createNewTab(), true);
194   - }
195   - }]
196   - },
197   -
198   - listeners: {
199   - tabchange: function(tabPanel, newCard, oldCard, eOpts ) {
200   - var newCardTree = this.getTreeFromPlotTab(newCard);
201   - var selectedNode = newCardTree.getSelectedNode();
202   - if (selectedNode == null)
203   - me.plotElementPanel.resetElement();
204   - else
205   - me.plotElementPanel.setElement(selectedNode.type,selectedNode.object, newCardTree);
206   - newCardTree.updateLinkedToMultiPlotMode();
207   - },
208   - scope: me
209   - }
210   - };
211   -
212   - Ext.apply (this , Ext.apply (arguments, myConf));
213   - }
  154 + init : function(config) {
  155 + var me = this;
  156 +
  157 + this.plotUI = config.plotUI;
  158 +
  159 + var myConf = {
  160 + plain: true,
  161 + bodyStyle: { background : '#dfe8f6' },
  162 + border : false,
  163 + defaults: {
  164 + border: false
  165 + },
  166 + tabBar:{
  167 + items:[
  168 + {
  169 + text:'+',
  170 + closable: false,
  171 + handler:function(btn,e){
  172 + var tabContent = me.addPlotNode(me.multiplot_object.createNewPlot(), true);
  173 + }
  174 + }
  175 + ],
  176 + listeners: {
  177 + beforedestroy: function(tabbar, eOpts) {
  178 + me.tabbar_destroy = true;
  179 + }
  180 + }
  181 + }
  182 + };
  183 +
  184 + Ext.apply (this , Ext.apply (arguments, myConf));
  185 + }
214 186 });
... ...
js/app/views/PlotComponents/PlotTree.js
... ... @@ -18,7 +18,6 @@ Ext.define(&#39;amdaPlotComp.PlotTree&#39;, {
18 18 //Link to the combo box to define the use of the simplified view
19 19 simplifiedViewCombo : null,
20 20  
21   - //Link to the combo to attach the tab to the multi plot mode
22 21  
23 22 //Link to the Plot Element Panel
24 23 plotElementPanel: null,
... ... @@ -63,7 +62,6 @@ Ext.define(&#39;amdaPlotComp.PlotTree&#39;, {
63 62 this.suspendLayouts();
64 63 this.buildPanelsNode();
65 64 this.simplifiedViewCombo.setValue(this.tabObject.get('tree-full-view'));
66   - this.linkToMultiPlotCombo.setValue(this.tabObject.get('multi-plot-linked'));
67 65 this.resumeLayouts(true);
68 66 },
69 67  
... ... @@ -853,10 +851,6 @@ Ext.define(&#39;amdaPlotComp.PlotTree&#39;, {
853 851 }
854 852 },
855 853  
856   - updateLinkedToMultiPlotMode : function() {
857   - this.plotTabContent.updateLinkedToMultiPlotMode(this.tabObject.get('multi-plot-linked'));
858   - },
859   -
860 854 init : function(config) {
861 855 var me = this;
862 856  
... ... @@ -891,21 +885,6 @@ Ext.define(&#39;amdaPlotComp.PlotTree&#39;, {
891 885 }
892 886 });
893 887  
894   - this.linkToMultiPlotCombo = Ext.create('Ext.form.field.Checkbox', {
895   - xtype: 'checkbox',
896   - boxLabel: 'Link to MultiPlot',
897   - listeners: {
898   - change: function(combo, newValue, oldValue, eOpts) {
899   - if (this.tabObject)
900   - {
901   - this.tabObject.set('multi-plot-linked', newValue);
902   - this.updateLinkedToMultiPlotMode();
903   - }
904   - },
905   - scope: this
906   - }
907   - });
908   -
909 888 var myConf = {
910 889 store: store,
911 890 rootVisible: false,
... ... @@ -959,8 +938,6 @@ Ext.define(&#39;amdaPlotComp.PlotTree&#39;, {
959 938 scope: this
960 939 },
961 940 '-', '->',
962   - this.linkToMultiPlotCombo,
963   - ' ',
964 941 this.simplifiedViewCombo
965 942 ]
966 943 };
... ...
js/app/views/PlotComponents/PlotZoomPlug.js
... ... @@ -26,7 +26,7 @@ Ext.define(&#39;amdaPlotComp.PlotZoomPlug&#39;, {
26 26 win: null,
27 27 form: null,
28 28 zoomType: '',
29   - tabId: '',
  29 + interactiveId: '',
30 30 panelId: -1,
31 31  
32 32 linkedTTCatNode: null,
... ... @@ -101,7 +101,7 @@ Ext.define(&#39;amdaPlotComp.PlotZoomPlug&#39;, {
101 101 /**
102 102 * creation of the window
103 103 */
104   - show: function (tabId, zoomType, panelId) {
  104 + show: function (interactiveId, zoomType, panelId) {
105 105 if (!this.win) {
106 106 this.win = new Ext.Window({
107 107 id: 'plot-zoom-win-' + this.hostCmp.ownerCt.getId(), // Plot window ID
... ... @@ -136,7 +136,7 @@ Ext.define(&#39;amdaPlotComp.PlotZoomPlug&#39;, {
136 136 Ext.PluginManager.register(this);
137 137 }
138 138  
139   - this.tabId = tabId;
  139 + this.interactiveId = interactiveId;
140 140 this.updateWinByType(zoomType, panelId);
141 141 this.win.show();
142 142 this.win.setPosition(0, 0);
... ... @@ -407,7 +407,7 @@ Ext.define(&#39;amdaPlotComp.PlotZoomPlug&#39;, {
407 407  
408 408 this.hostCmp.callInteractivePlot({
409 409 'action': 'zoom',
410   - 'tabId': this.tabId,
  410 + 'interactiveId': this.interactiveId,
411 411 'panelId': this.panelId,
412 412 'axeId': this.zoomType,
413 413 'min': minZoom,
... ... @@ -423,7 +423,7 @@ Ext.define(&#39;amdaPlotComp.PlotZoomPlug&#39;, {
423 423 handler: function () {
424 424 this.hostCmp.callInteractivePlot({
425 425 'action': 'undozoom',
426   - 'tabId': this.tabId,
  426 + 'interactiveId': this.interactiveId,
427 427 'panelId': this.panelId,
428 428 'axeId': this.zoomType
429 429 });
... ...
js/app/views/PlotTabResultUI.js
... ... @@ -22,8 +22,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
22 22  
23 23 panelImage : null,
24 24 crtContext : null,
25   - tabId : '',
26   - multiPlotCheck : null,
  25 + interactiveId : '',
27 26 navToolBar : null,
28 27 isTTNavBar : false,
29 28 crtTTFileIndex : 0,
... ... @@ -55,12 +54,6 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
55 54 return 'data/'+sessionID +'/RES/'+resultFolder+ '/' + plotFile;
56 55 },
57 56  
58   - getInteractiveMultiPlotState: function() {
59   - if (!this.multiPlotCheck)
60   - return false;
61   - return this.multiPlotCheck.getValue();
62   - },
63   -
64 57 toPixelOnSourceImage : function(value) {
65 58 return value*100/this.sliderPage.getValue();
66 59 },
... ... @@ -147,7 +140,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
147 140 me.contextualMenu.add({
148 141 text:'Zoom on Time Axis',
149 142 handler : function(item, e) {
150   - zoomPlugin.show(me.tabId, axis.id, panelContext.id);
  143 + zoomPlugin.show(me.interactiveId, axis.id, panelContext.id);
151 144 zoomPlugin.resetMinMaxValue();
152 145 me.panelImage.startZoom(true, 0/*me.toPixelOnResultImage(panelContext.y)*/, size.height /*me.toPixelOnResultImage(panelContext.height)*/, onMinTimeSelection, onMaxTimeSelection);
153 146 },
... ... @@ -156,7 +149,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
156 149 insertIntervalItem = {
157 150 text:'Insert Interval in TimeTable or Catalog',
158 151 handler : function(item, e) {
159   - zoomPlugin.show(me.tabId, axis.id, panelContext.id);
  152 + zoomPlugin.show(me.interactiveId, axis.id, panelContext.id);
160 153 zoomPlugin.resetMinMaxValue();
161 154 me.panelImage.startZoom(true, 0/*me.toPixelOnResultImage(panelContext.y)*/, size.height /*me.toPixelOnResultImage(panelContext.height)*/, onMinTimeSelection, onMaxTimeSelection);
162 155 },
... ... @@ -167,7 +160,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
167 160 me.contextualMenu.add({
168 161 text:'Zoom on Y Left Axis',
169 162 handler : function(item, e) {
170   - zoomPlugin.show(me.tabId, axis.id, panelContext.id);
  163 + zoomPlugin.show(me.interactiveId, axis.id, panelContext.id);
171 164 zoomPlugin.resetMinMaxValue();
172 165 me.panelImage.startZoom(false, me.toPixelOnResultImage(panelContext.x), me.toPixelOnResultImage(panelContext.width), onMinYValueSelection, onMaxYValueSelection);
173 166 }
... ... @@ -177,7 +170,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
177 170 me.contextualMenu.add({
178 171 text:'Zoom on Y Right Axis',
179 172 handler : function(item, e) {
180   - zoomPlugin.show(me.tabId, axis.id, panelContext.id);
  173 + zoomPlugin.show(me.interactiveId, axis.id, panelContext.id);
181 174 zoomPlugin.resetMinMaxValue();
182 175 me.panelImage.startZoom(false, me.toPixelOnResultImage(panelContext.x), me.toPixelOnResultImage(panelContext.width), onMinYValueSelection, onMaxYValueSelection);
183 176 }
... ... @@ -187,7 +180,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
187 180 me.contextualMenu.add({
188 181 text:'Zoom on X Axis',
189 182 handler : function(item, e) {
190   - zoomPlugin.show(me.tabId, axis.id, panelContext.id);
  183 + zoomPlugin.show(me.interactiveId, axis.id, panelContext.id);
191 184 zoomPlugin.resetMinMaxValue();
192 185 me.panelImage.startZoom(true, me.toPixelOnResultImage(panelContext.y), me.toPixelOnResultImage(panelContext.height), onMinXValueSelection, onMaxXValueSelection);
193 186 }
... ... @@ -205,6 +198,11 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
205 198 me.contextualMenu.add(insertIntervalItem);
206 199 }
207 200 },
  201 +
  202 + getAxisValue: function(axis, pixelMin, pixelMax, pixelVal) {
  203 + var val = amdaPlotComp.PlotContextManager.toAxisValue(axis, pixelMin, pixelMax, pixelVal);
  204 + return parseFloat(val).toPrecision(5);
  205 + },
208 206  
209 207 createPlotImage: function(resultFolder, plotFile) {
210 208 var me = this;
... ... @@ -259,16 +257,16 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
259 257 xText = crtTime.toJSON();
260 258 break;
261 259 case 'y-left' :
262   - yLeftText = parseFloat(amdaPlotComp.PlotContextManager.toAxisValue(axis, panel.plotArea.y+panel.plotArea.height, panel.plotArea.y, sourceYPos).toFixed(2));
  260 + yLeftText = me.getAxisValue(axis, panel.plotArea.y+panel.plotArea.height, panel.plotArea.y, sourceYPos);
263 261 break;
264 262 case 'y-right' :
265   - yRightText = parseFloat(amdaPlotComp.PlotContextManager.toAxisValue(axis, panel.plotArea.y+panel.plotArea.height, panel.plotArea.y, sourceYPos).toFixed(2));
  263 + yRightText = me.getAxisValue(axis, panel.plotArea.y+panel.plotArea.height, panel.plotArea.y, sourceYPos);
266 264 break;
267 265 case 'xaxis_id' :
268   - xText = parseFloat(amdaPlotComp.PlotContextManager.toAxisValue(axis, panel.plotArea.x, panel.plotArea.x+panel.plotArea.width, sourceXPos).toFixed(2));
  266 + xText = me.getAxisValue(axis, panel.plotArea.x, panel.plotArea.x+panel.plotArea.width, sourceXPos);
269 267 break;
270 268 case 'epochAxis' :
271   - xText = parseFloat(amdaPlotComp.PlotContextManager.toAxisValue(axis, panel.plotArea.x, panel.plotArea.x+panel.plotArea.width, sourceXPos).toFixed(2));
  269 + xText = me.getAxisValue(axis, panel.plotArea.x, panel.plotArea.x+panel.plotArea.width, sourceXPos);
272 270 break;
273 271 }
274 272  
... ... @@ -312,7 +310,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
312 310 var crtTimestamp = amdaPlotComp.PlotContextManager.toAxisValue(timeAxisContext, panel.plotArea.x, panel.plotArea.x+panel.plotArea.width, sourceXPos);
313 311 var crtTime = new Date(crtTimestamp*1000);
314 312 crtTime = Ext.Date.add(crtTime, Ext.Date.MINUTE, crtTime.getTimezoneOffset());
315   - me.callInteractivePlot({'action' : 'instant', 'tabId' : this.tabId, 'panelId' : panel.id, 'time' : crtTime});
  313 + me.callInteractivePlot({'action' : 'instant', 'interactiveId' : this.interactiveId, 'panelId' : panel.id, 'time' : crtTime});
316 314 },
317 315 scope: me
318 316 },
... ... @@ -333,7 +331,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
333 331 handler : function ()
334 332 {
335 333 var extendShiftPlugin = this.getPlugin('plot-extendshift-plugin-id');
336   - extendShiftPlugin.show(me.tabId);
  334 + extendShiftPlugin.show(me.interactiveId);
337 335 },
338 336 scope: me
339 337 },
... ... @@ -358,7 +356,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
358 356 me.hiddenForm.getForm().submit({
359 357 params: {
360 358 sessionId: sessionID,
361   - tabId : me.tabId
  359 + interactiveId : me.interactiveId
362 360 },
363 361 success: function(form, action) {},
364 362 failure: function(form, action) {}
... ... @@ -388,13 +386,6 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
388 386  
389 387 this.updateTimeTableInfo();
390 388  
391   - if (this.multiPlotCheck)
392   - {
393   - this.disableSynchronize = true;
394   - this.multiPlotCheck.setValue(configResult.multiplot);
395   - this.disableSynchronize = false;
396   - }
397   -
398 389 this.panelImage.setSrc(this.getImageUrl(configResult.folder, configResult.plotFile));
399 390  
400 391 var size = this.getImageSize();
... ... @@ -408,15 +399,15 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
408 399 if (!this.navToolBar)
409 400 return;
410 401  
411   - var ttNameField = this.navToolBar.items.get('tt-table-'+this.tabId);
  402 + var ttNameField = this.navToolBar.items.get('tt-table-'+this.interactiveId);
412 403 if (ttNameField)
413 404 ttNameField.setValue(this.crtContext.page.ttName);
414 405  
415   - var ttNumberField = this.navToolBar.items.get('tt-number-'+this.tabId);
  406 + var ttNumberField = this.navToolBar.items.get('tt-number-'+this.interactiveId);
416 407 if (ttNumberField)
417 408 ttNumberField.setValue(this.crtContext.page.ttIndex + 1);
418 409  
419   - var ttTotalField = this.navToolBar.items.get('tt-total-'+this.tabId);
  410 + var ttTotalField = this.navToolBar.items.get('tt-total-'+this.interactiveId);
420 411 if (ttTotalField)
421 412 ttTotalField.setValue(this.crtContext.page.ttNbIntervals);
422 413 },
... ... @@ -425,9 +416,8 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
425 416 loadMask.show(true);
426 417  
427 418 var plotModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.plot.id);
428   - var multiPlotState = plotModule.getInteractiveMultiPlotState();
429 419  
430   - AmdaAction.interactivePlot(obj, multiPlotState, function (result, e) {
  420 + AmdaAction.interactivePlot(obj, function (result, e) {
431 421 loadMask.hide();
432 422 var t = e.getTransaction();
433 423 if (e.status)
... ... @@ -456,28 +446,12 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
456 446 if (this.navToolBar)
457 447 this.navToolBar.removeAll(true);
458 448  
459   - this.multiPlotCheck = Ext.create('Ext.form.field.Checkbox', {
460   - boxLabel : 'Linked to Multi Plot',
461   - scope: this,
462   - handler: function(check, checked) {
463   - if (!this.disableSynchronize)
464   - this.callInteractivePlot({'action' : 'synchronize', 'tabId' : this.tabId});
465   - },
466   - scope: this
467   - });
468   -
469 449 var commonItemsCfg = [
470 450 '-',
471 451 {
472 452 xtype: 'tbspacer',
473 453 width: 20
474 454 },
475   - this.multiPlotCheck,
476   - {
477   - xtype: 'tbspacer',
478   - width: 2
479   - },
480   - '-',
481 455 '->',
482 456 {
483 457 text: 'Get HST Data',
... ... @@ -515,7 +489,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
515 489 }
516 490 else
517 491 --ttintervalIndex;
518   - this.callInteractivePlot({'action' : 'goto', 'tabId' : this.tabId, 'ttFileIndex' : ttFileIndex, 'intIndex' : ttintervalIndex});
  492 + this.callInteractivePlot({'action' : 'goto', 'interactiveId' : this.interactiveId, 'ttFileIndex' : ttFileIndex, 'intIndex' : ttintervalIndex});
519 493 }
520 494 },
521 495 '-',
... ... @@ -534,7 +508,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
534 508 else
535 509 ++ttintervalIndex;
536 510  
537   - this.callInteractivePlot({'action' : 'goto', 'tabId' : this.tabId, 'ttFileIndex' : ttFileIndex, 'intIndex' : ttintervalIndex});
  511 + this.callInteractivePlot({'action' : 'goto', 'interactiveId' : this.interactiveId, 'ttFileIndex' : ttFileIndex, 'intIndex' : ttintervalIndex});
538 512 }
539 513 },
540 514 '-',
... ... @@ -542,17 +516,17 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
542 516 text: 'Go to Interval #',
543 517 scope: this,
544 518 handler: function(bt){
545   - var ttGotoNumberField = this.navToolBar.items.get('tt-goto-number-'+this.tabId);
  519 + var ttGotoNumberField = this.navToolBar.items.get('tt-goto-number-'+this.interactiveId);
546 520 var goToIndex = ttGotoNumberField.getValue() - 1;
547 521 if ((goToIndex < 0) || (goToIndex >= this.crtContext.page.ttNbIntervals))
548 522 myDesktopApp.errorMsg('This interval number is outside of the current timeTable');
549 523 else
550   - this.callInteractivePlot({'action' : 'goto', 'tabId' : this.tabId, 'ttFileIndex' : this.crtTTFileIndex, 'intIndex' : goToIndex});
  524 + this.callInteractivePlot({'action' : 'goto', 'interactiveId' : this.interactiveId, 'ttFileIndex' : this.crtTTFileIndex, 'intIndex' : goToIndex});
551 525 }
552 526 },
553 527 {
554 528 xtype: 'numberfield',
555   - id : 'tt-goto-number-'+this.tabId,
  529 + id : 'tt-goto-number-'+this.interactiveId,
556 530 hideTrigger: true,
557 531 width: 50,
558 532 minValue: 1
... ... @@ -562,7 +536,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
562 536 ' ',
563 537 {
564 538 xtype: 'textfield',
565   - id: 'tt-table-'+this.tabId,
  539 + id: 'tt-table-'+this.interactiveId,
566 540 labelAlign: 'right',
567 541 labelWidth: 30,
568 542 fieldLabel: 'Table',
... ... @@ -571,7 +545,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
571 545 },
572 546 {
573 547 xtype: 'textfield',
574   - id: 'tt-number-'+this.tabId,
  548 + id: 'tt-number-'+this.interactiveId,
575 549 labelAlign: 'right',
576 550 labelWidth: 30,
577 551 fieldLabel: 'Int #',
... ... @@ -580,7 +554,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
580 554 },
581 555 {
582 556 xtype: 'textfield',
583   - id: 'tt-total-'+this.tabId,
  557 + id: 'tt-total-'+this.interactiveId,
584 558 labelAlign: 'right',
585 559 labelWidth: 30,
586 560 fieldLabel: 'Total',
... ... @@ -595,7 +569,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
595 569 text: 'Backward',
596 570 scope: this,
597 571 handler: function(){
598   - this.callInteractivePlot({'action' : 'backward', 'tabId' : this.tabId});
  572 + this.callInteractivePlot({'action' : 'backward', 'interactiveId' : this.interactiveId});
599 573 }
600 574 },
601 575 '-',
... ... @@ -603,7 +577,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
603 577 text: '1/2 Backward',
604 578 scope: this,
605 579 handler: function(){
606   - this.callInteractivePlot({'action' : 'halfbackward', 'tabId' : this.tabId});
  580 + this.callInteractivePlot({'action' : 'halfbackward', 'interactiveId' : this.interactiveId});
607 581 }
608 582 },
609 583 '-',
... ... @@ -611,7 +585,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
611 585 text: '1/2 Forward',
612 586 scope: this,
613 587 handler: function(){
614   - this.callInteractivePlot({'action' : 'halfforward', 'tabId' : this.tabId});
  588 + this.callInteractivePlot({'action' : 'halfforward', 'interactiveId' : this.interactiveId});
615 589 }
616 590 },
617 591 '-',
... ... @@ -619,7 +593,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
619 593 text: 'Forward',
620 594 scope: this,
621 595 handler: function(){
622   - this.callInteractivePlot({'action' : 'forward', 'tabId' : this.tabId});
  596 + this.callInteractivePlot({'action' : 'forward', 'interactiveId' : this.interactiveId});
623 597 }
624 598 }];
625 599 }
... ... @@ -649,7 +623,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
649 623  
650 624 init: function(configResult){
651 625 this.crtContext = configResult.context;
652   - this.tabId = configResult.tabId;
  626 + this.interactiveId = configResult.interactiveId;
653 627  
654 628 this.coordinatesField = new Ext.toolbar.TextItem({
655 629 width: 300,
... ... @@ -700,13 +674,6 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
700 674  
701 675 this.updateTimeTableInfo();
702 676  
703   - if (this.multiPlotCheck)
704   - {
705   - this.disableSynchronize = true;
706   - this.multiPlotCheck.setValue(configResult.multiplot);
707   - this.disableSynchronize = false;
708   - }
709   -
710 677 var plotResultTabPanelConfig = {
711 678 preventHeader : true,
712 679 autoScroll: true,
... ...
js/app/views/PlotUI.js
... ... @@ -10,454 +10,210 @@
10 10  
11 11  
12 12 Ext.define('amdaUI.PlotUI', {
13   - extend: 'Ext.container.Container',
14   - alias: 'widget.newPanelPlot',
  13 + extend: 'Ext.container.Container',
  14 + alias: 'widget.newPanelPlot',
15 15  
16   - requires: [
17   - 'amdaModel.DownloadNode',
18   - 'amdaModel.Download',
19   - 'amdaUI.TimeSelectorUI',
20   - 'amdaPlotComp.PlotTabPanel',
21   - 'amdaPlotComp.PlotOutputForm',
22   - 'amdaPlotComp.PlotElementPanel'
  16 + requires: [
  17 + 'amdaModel.DownloadNode',
  18 + 'amdaModel.Download',
  19 + 'amdaPlotComp.PlotTabPanel'
23 20 ],
24 21  
25   - formPanel: null,
26   -
27   - multiPlotIntervalPanel : null,
28   -
29   - plotOutput: null,
30   -
31   - plotTabs : null,
32   -
33   - plotElement : null,
34   -
35   - constructor: function(config) {
36   - this.init(config);
37   - this.callParent(arguments);
38   - if (this.object)
39   - this.setObject(this.object);
40   - },
41   -
42   - setObject : function(object) {
43   - this.object = object;
44   - this.plotOutput.setObject(this.object);
45   - this.plotTabs.setRequestObject(this.object);
46   - this.timeSelector.intervalSel.setInterval(this.object.get('startDate'), this.object.get('stopDate'));
47   - this.addTTs(this.object.get('timeTables'));
48   - },
49   -
50   - /**
51   - * overwrite metod called by Save button
52   - */
53   - overwriteProcess : function(btn)
54   - {
55   - if (btn == 'cancel') return;
56   -
57   - this.saveProcess(true);
58   - },
59   -
60   -
61   - /**
62   - * save method called by Save button to launch the save process
63   - */
64   - saveProcess : function(toRename) {
65   - var plotModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.plot.id);
66   - if (!plotModule)
67   - return;
68   -
69   - if (toRename) {
70   - plotModule.linkedNode.set('object',this.object);
71   - plotModule.linkedNode.update();
72   - }
73   - else {
74   - //Save
75   - if (this.object.get('id') != '') {
76   - //Duplicate request
77   - plotModule.createLinkedNode();
78   - plotModule.linkedNode.set('object',this.object);
79   - }
80   - plotModule.linkedNode.create();
81   - }
82   - },
  22 + formPanel: null,
  23 + plotTabs : null,
  24 +
  25 + constructor: function(config) {
  26 + this.init(config);
  27 + this.callParent(arguments);
  28 + if (this.object)
  29 + this.setObject(this.object);
  30 + },
  31 +
  32 + setObject : function(object) {
  33 + this.object = object;
  34 + if (this.object.plots().count() == 0) {
  35 + this.object.createNewPlot();
  36 + }
  37 + this.plotTabs.setMultiplotObject(this.object);
  38 + },
  39 +
  40 + resetProcess : function(){
  41 + var plotModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.plot.id);
  42 + plotModule.createLinkedNode();
  43 + var obj = null;
  44 + if ((arguments.length > 0) && (arguments[0] != null)) {
  45 + obj = arguments[0];
  46 + }
  47 + plotModule.createObject(obj);
  48 + this.setObject(plotModule.linkedNode.get('object'));
  49 + },
  50 +
  51 + getDataProcess : function(){
  52 + if ( this.updateObject() ) {
  53 + var plotTab = this.plotTabs.getCurrentPlotTabContent();
  54 + if (!plotTab || !plotTab.plotNode)
  55 + return;
  56 + plotTab.getDataProcess();
  57 + }
  58 + },
83 59  
84   - resetProcess : function(){
85   - var plotModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.plot.id);
86   - plotModule.createLinkedNode();
87   - var obj = null;
88   - if ((arguments.length > 0) && (arguments[0] != null)) {
89   - obj = arguments[0];
90   - }
91   - plotModule.createObject(obj);
92   - this.setObject(plotModule.linkedNode.get('object'));
93   - },
94   -
95   - getDataProcess : function(){
96   - this.updateObject();
97   - // plot was not called - form only
98   - if (this.object.get('last-plotted-tab') == 0) {
99   - this.object.set('last-plotted-tab', this.plotTabs.getSelectedTabId());
100   - }
101   - var downObject = amdaModel.DownloadNode.decodeObject(this.object);
102   - amdaModel.DownloadNode.set('object',Ext.create('amdaModel.Download',downObject));
103   -
104   - amdaModel.DownloadNode.editInModule();
105   - },
106   -
107   - addParameter : function(node){
108   - var crtTree = this.plotTabs.getTreeFromPlotTab(this.plotTabs.getActiveTab());
109   - crtTree.dropRecord(node,null,'append');
110   - },
  60 + addParameter : function(node, updateTime){
  61 + var crtTree = this.plotTabs.getTreeFromPlotTab(this.plotTabs.getActiveTab());
  62 + if (crtTree) {
  63 + crtTree.dropRecord(node,null,'append');
  64 + if (updateTime) {
  65 + if((node.get('globalStart') != null) && (node.get('globalStop') != null) && node.get('globalStart') != 'depending on mission' && node.get('isParameter')) {
  66 + this.setTimeFromData(node.getTimeFromNode(node));
  67 + }
  68 + }
  69 + }
  70 + },
  71 +
  72 + editPlot : function(plotNode) {
  73 + this.plotTabs.addPlotNode(plotNode, true);
  74 + },
  75 +
  76 + reloadPlot : function(plotNode) {
  77 + this.plotTabs.reloadPlot(plotNode);
  78 + },
111 79  
112   - /**
  80 + /**
113 81 * plot method called by 'Do Plot' button to launch the plot process
114 82 */
115   - doPlot : function(){
116   -
117   - this.updateObject();
118   - this.object.set('last-plotted-tab', this.plotTabs.getSelectedTabId());
119   - var plotModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.plot.id);
120   - if (plotModule)
121   - plotModule.linkedNode.execute();
122   - },
123   -
124   - /**
125   - * Check if changes were made before closing window
126   - * @return false
127   - */
128   - fclose : function() {
129   - var module = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.plot.id);
130   - if (module)
131   - module.closeInteractiveSession();
132   -
133   - return this.object.isDirty();
134   - },
135   -
136   - /**
137   - * update time selector of this.object from form
138   - */
139   - updateObject : function(){
140   - var timeSource = this.timeSelector.getActiveTimeSource();
141   -
142   - var multiPlotForm = this.timeSelector.getForm();
143   - multiPlotForm.updateRecord(this.object);
144   - this.object.set('timesrc', timeSource);
145   - if (timeSource === amdaModel.AmdaTimeObject.inputTimeSrc[0])
146   - this.object.set('timeTables',this.timeSelector.TTGrid.getStore().data.items);
147   - this.plotTabs.updateTimeObject();
148   - },
149   -
150   - addTT : function(newTTName,newTTid,timeSelectorId) {
151   - var crtTimeSelector = Ext.getCmp(timeSelectorId);
152   - if (crtTimeSelector)
153   - crtTimeSelector.addTT(newTTName,newTTid);
154   - },
155   -
156   - addTTs : function(TTarray) {
157   - // set TTTab
158   - this.timeSelector.setTTTab(TTarray);
159   - },
160   -
161   - /**
162   - * Set Start-Stop from parameter info (Local & MyData)
163   - */
164   - setTimeFromData : function(obj) {
165   - if (!obj.start || !obj.stop)
166   - return;
167   - var dateStart = new Date(obj.start.replace(/[T|Z]/g,' ').replace(/\-/g,'\/'));
168   - var dateStop = new Date(obj.stop.replace(/[T|Z]/g,' ').replace(/\-/g,'\/'));
169   -
170   - for (var i = 0; i < this.plotTabs.items.getCount(); ++i) {
171   - var plotTab = this.plotTabs.items.getAt(i).items.getAt(0);
172   - plotTab.items.getAt(1).intervalSel.setInterval(dateStart, dateStop);
173   - //TBD plotTab.updateTimeObject();
174   - }
175   -
176   - this.timeSelector.intervalSel.setInterval(dateStart, dateStop);
177   - },
178   -
179   - forceActiveTab : function(tabId) {
180   - for (var i = 0; i < this.plotTabs.items.getCount(); ++i) {
181   - var plotTab = this.plotTabs.items.getAt(i).items.getAt(0);
182   - if (plotTab.tabId == tabId) {
183   - this.plotTabs.setActiveTab(i);
184   - return;
185   - }
186   - }
187   - },
188   -
189   - updatePlotTabName: function(tabId, name) {
190   - var me = this;
191   - this.object.tabs().each(function (tabObject) {
192   - if (tabId == tabObject.getId()) {
193   - tabObject.set('tab-name', name);
194   - me.plotTabs.updatePlotTabs();
195   - }
196   - });
197   - },
198   -
199   - insertPlotTab : function(tabData) {
200   - var newTab = this.object.createNewTab(tabData);
201   - this.plotTabs.addPlotTab(newTab,true);
202   - },
203   -
204   - updateLinkedToMultiPlotMode : function(isLinkedToMultiPlotMode) {
205   - this.timeSelector.setVisible(isLinkedToMultiPlotMode);
206   - },
207   -
208   - keepOnlySelectedTabInObject: function(showWarning, onSuccess) {
209   - if (this.object.tabs().count() == 1) {
210   - if (onSuccess) {
211   - onSuccess();
212   - }
213   - return;
214   - }
215   -
216   - var me = this;
217   - var removeFunc = function() {
218   - var tabsToRemove = [];
219   - var selectedTabFound = false;
220   - me.object.tabs().each(function(tab) {
221   - if (tab.get('id') != me.object.get('active-tab-id')) {
222   - tabsToRemove.push(tab);
223   - }
224   - else {
225   - selectedTabFound = true;
226   - }
227   - });
228   - if (!selectedTabFound) {
229   - myDesktopApp.errorMsg('Cannot retrieve selected tab');
230   - return false;
231   - }
232   - if (tabsToRemove.length > 0) {
233   - me.object.tabs().remove(tabsToRemove);
234   - }
235   - return true;
236   - };
237   -
238   - if (!showWarning) {
239   - if (removeFunc()) {
240   - if (onSuccess) {
241   - onSuccess();
242   - }
243   - }
244   - return;
245   - }
246   -
247   -
248   - Ext.Msg.show( { title : 'Warning',
249   - msg: 'Active plot will be saved, but other ones will be lost.<br/>Do you want to continue?',
250   - width: 300,
251   - buttons: Ext.Msg.OKCANCEL,
252   - fn: function(btn) {
253   - if (btn == 'cancel') return;
254   -
255   - if (removeFunc()) {
256   - if (onSuccess) {
257   - onSuccess();
258   - }
259   - }
260   - return;
261   - },
262   - scope: me
263   - });
264   - },
265   -
266   - savePlotRequest : function(allTabs) {
267   - var plotModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.plot.id);
268   - if (!plotModule)
269   - return;
270   - this.updateObject();
271   - this.object.set('active-tab-id', this.plotTabs.getSelectedTabId());
272   - var me = this;
273   -
274   - if ((this.object.get('id') != '') && (plotModule.linkedNode.get('text') == this.object.get('name'))) {
275   - //update existing request
276   - if (!allTabs) {
277   - this.keepOnlySelectedTabInObject(true, function() {
278   - plotModule.linkedNode.update();
279   - });
280   - }
281   - else {
282   - plotModule.linkedNode.update();
283   - }
284   - return;
285   - }
286   -
287   - //save new request
288   - var me = this;
289   - plotModule.linkedNode.isValidName(this.object.get('name'), function (res) {
290   - if (!res) {
291   - myDesktopApp.errorMsg('Error during object validation');
292   - return;
293   - }
294   - if (!res.valid) {
295   - if (res.error) {
296   - if (res.error.search('subtree') != -1) {
297   - Ext.Msg.show( { title : 'Warning',
298   - msg: res.error + '<br/>Do you want to overwrite it?',
299   - width: 300,
300   - buttons: Ext.Msg.OKCANCEL,
301   - icon: Ext.Msg.WARNING,
302   - fn : me.overwriteProcess,
303   - scope : me
304   - });
305   - }
306   - else {
307   - myDesktopApp.errorMsg(res.error);
308   - }
309   - }
310   - else {
311   - myDesktopApp.errorMsg('Invalid object name');
312   - }
313   - return;
314   - }
315   - if (!allTabs) {
316   - me.keepOnlySelectedTabInObject((me.object.get('id') == ''), function() {
317   - me.saveProcess(false);
318   - me.setObject(me.object);
319   - });
320   - }
321   - else {
322   - me.saveProcess(false);
323   - }
324   - });
325   - },
  83 + doPlot : function(){
  84 + if ( this.updateObject(false) ) {
  85 + var plotTab = this.plotTabs.getCurrentPlotTabContent();
  86 + if (plotTab)
  87 + plotTab.doPlot();
  88 + }
  89 + },
  90 +
  91 + /**
  92 + * Check if changes were made before closing window
  93 + * @return false
  94 + */
  95 + fclose : function() {
  96 + var module = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.plot.id);
  97 + if (module)
  98 + module.closeInteractiveSession();
  99 +
  100 + return this.object.isDirty();
  101 + },
  102 +
  103 + /**
  104 + * update time selector of this.object from form
  105 + */
  106 + updateObject : function(acceptEmptyTTList = true){
  107 + var plotTab = this.plotTabs.getCurrentPlotTabContent();
  108 + if (plotTab)
  109 + return plotTab.isValidRequest(acceptEmptyTTList);
  110 + return false;
  111 + },
  112 +
  113 + updateTabs : function() {
  114 + this.plotTabs.updatePlotTabs();
  115 + },
  116 +
  117 + updateRequestName : function(renamedNode) {
  118 + this.plotTabs.updateRequestName(renamedNode);
  119 + },
  120 +
  121 + addTT : function(newTTName,newTTid,timeSelectorId) {
  122 + var crtTimeSelector = Ext.getCmp(timeSelectorId);
  123 + if (crtTimeSelector)
  124 + crtTimeSelector.addTT(newTTName,newTTid);
  125 + },
  126 +
  127 + /**
  128 + * Set Start-Stop from parameter info (Local & MyData)
  129 + */
  130 + setTimeFromData : function(obj) {
  131 + if (!obj.start || !obj.stop)
  132 + return;
  133 + var dateStart = new Date(obj.start.replace(/[T|Z]/g,' ').replace(/\-/g,'\/'));
  134 + var dateStop = new Date(obj.stop.replace(/[T|Z]/g,' ').replace(/\-/g,'\/'));
  135 +
  136 + var plotTab = this.plotTabs.getCurrentPlotTabContent();
  137 + if (plotTab)
  138 + plotTab.setTime(dateStart, dateStop);
  139 + },
  140 +
  141 + savePlotRequest : function() {
  142 + if (this.updateObject(true)) {
  143 + var plotTab = this.plotTabs.getCurrentPlotTabContent();
  144 + if (plotTab)
  145 + plotTab.savePlot();
  146 + }
  147 + },
326 148  
327   - init : function(config) {
328   - this.timeSelector = new amdaUI.TimeSelectorUI( { id: 'multiPlotTimeSelector' + config.id, title : 'MultiPlot Time Selection', border : false, collapsible : true, collapseDirection : 'bottom', visible : false, flex: 2 } );
329   -
330   - this.plotOutput = new amdaPlotComp.PlotOutputForm({flex: 2, collapseDirection : 'bottom', collapsible : true });
331   -
332   - this.plotElement = new amdaPlotComp.PlotElementPanel({flex: 4});
333   -
334   - this.plotTabs = new amdaPlotComp.PlotTabPanel({flex: 4, plotElementPanel : this.plotElement, plotUI : this});
335   -
336   - this.optionsPanel = new Ext.form.Panel({
337   - layout: {
338   - type: 'vbox',
339   - pack: 'start',
340   - align: 'stretch'
341   - },
342   - bodyStyle: { background : '#dfe8f6' },
343   - defaults: {
344   - border: false
345   - },
346   - items: [
347   - this.plotElement,
348   - this.plotOutput
349   - ]
350   - });
351   -
352   - this.formPanel = new Ext.form.Panel({
353   - region: 'center',
354   - layout: {
355   - type: 'hbox',
356   - pack: 'start',
357   - align: 'stretch'
358   - },
359   - bodyStyle: { background : '#dfe8f6' },
360   - defaults: {
361   - border: false
362   - },
363   - items: [
364   - {
365   - xtype : 'panel',
366   - layout: {
367   - type: 'vbox',
368   - pack: 'start',
369   - align: 'stretch'
370   - },
371   - bodyStyle: { background : '#dfe8f6' },
372   - defaults: {
373   - border: false
374   - },
375   - flex: 1,
376   - items: [
377   - this.plotTabs,
378   - this.timeSelector // this.multiPlotIntervalPanel
379   - ]
380   - },
381   - {
382   - xtype : 'panel',
383   - layout: 'fit',
384   - bodyStyle: { background : '#dfe8f6' },
385   - defaults: {
386   - border: false
387   - },
388   - flex: 1,
389   - items: [
390   - this.optionsPanel
391   - ]
392   - }
393   - ],
394   - fbar: [
395   - {
396   - xtype: 'button',
397   - text: 'Plot',
398   - scope: this,
399   - handler: function(button) {
400   - this.doPlot();
401   - }
402   - },' ', {
403   - xtype: 'button',
404   - text: 'Get Data',
405   - scope: this,
406   - handler: function(button) {
407   - this.getDataProcess();
408   - }
409   - },' ', {
410   - xtype: 'button',
411   - text: 'Reset',
412   - scope: this,
413   - handler: function(button) {
414   - this.resetProcess();
415   - }
416   - },
417   - '->', '-', {
418   - xtype: 'splitbutton',
419   - text: 'Save All Tabs',
420   - menu: {
421   - items: [
422   - {
423   - text: 'Save Current Tab',
424   - scope: this,
425   - handler: function() {
426   - this.savePlotRequest(false);
427   - }
428   - },
429   - ]
430   - },
431   - scope: this,
432   - handler: function(button) {
433   - this.savePlotRequest(true);
434   - }
435   - }
436   - ]
437   - });
438   -
439   - var myConf = {
440   - layout: 'border',
441   - items: [
442   - this.formPanel,
443   - {
444   - xtype: 'panel',
445   - region: 'south',
446   - title: 'Information',
447   - collapsible: true,
448   - collapseMode: 'header',
449   - height: 100,
450   - autoHide: false,
451   - bodyStyle: 'padding:5px',
452   - iconCls: 'icon-information',
453   - loader: {
454   - autoLoad: true,
455   - url: helpDir+'plotHOWTO'
456   - }
457   - }
458   - ]
459   - };
460   -
461   - Ext.apply(this, Ext.apply(arguments, myConf));
462   - }
  149 + init : function(config) {
  150 + this.plotTabs = new amdaPlotComp.PlotTabPanel({plotUI : this});
  151 +
  152 + this.formPanel = new Ext.form.Panel({
  153 + region: 'center',
  154 + layout: 'fit',
  155 + bodyStyle: { background : '#dfe8f6' },
  156 + defaults: {
  157 + border: false
  158 + },
  159 + items: [
  160 + this.plotTabs
  161 + ],
  162 + fbar: [
  163 + {
  164 + xtype: 'button',
  165 + text: 'Plot',
  166 + scope: this,
  167 + handler: function(button) {
  168 + this.doPlot();
  169 + }
  170 + },' ', {
  171 + xtype: 'button',
  172 + text: 'Get Data',
  173 + scope: this,
  174 + handler: function(button) {
  175 + this.getDataProcess();
  176 + }
  177 + },' ', {
  178 + xtype: 'button',
  179 + text: 'Reset',
  180 + scope: this,
  181 + handler: function(button) {
  182 + this.resetProcess();
  183 + }
  184 + },'->', '-', {
  185 + xtype: 'button',
  186 + text: 'Save',
  187 + scope: this,
  188 + handler: function(button) {
  189 + this.savePlotRequest();
  190 + }
  191 + }
  192 + ]
  193 + });
  194 +
  195 + var myConf = {
  196 + layout: 'border',
  197 + items: [
  198 + this.formPanel,
  199 + {
  200 + xtype: 'panel',
  201 + region: 'south',
  202 + title: 'Information',
  203 + collapsible: true,
  204 + collapseMode: 'header',
  205 + height: 100,
  206 + autoHide: false,
  207 + bodyStyle: 'padding:5px',
  208 + iconCls: 'icon-information',
  209 + loader: {
  210 + autoLoad: true,
  211 + url: helpDir+'plotHOWTO'
  212 + }
  213 + }
  214 + ]
  215 + };
  216 +
  217 + Ext.apply(this, Ext.apply(arguments, myConf));
  218 + }
463 219 });
... ...
js/app/views/TimeSelectorUI.js
... ... @@ -61,6 +61,20 @@ Ext.define(&#39;amdaUI.TimeSelectorUI&#39;, {
61 61 getActiveTimeSource: function() {
62 62 return this.timeSrc.getActiveTab().getItemId();
63 63 },
  64 +
  65 + isValid: function(acceptEmptyTTList = true) {
  66 + if (this.getActiveTimeSource() === amdaModel.AmdaTimeObject.inputTimeSrc[0]) {
  67 + //TimeTables
  68 + if (acceptEmptyTTList)
  69 + return true;
  70 + return (this.TTGrid.getStore().count() > 0);
  71 + }
  72 + else {
  73 + //Interval
  74 + return this.intervalSel.isValid();
  75 + }
  76 + return true;
  77 + },
64 78  
65 79 initComponent: function() {
66 80 this.activeField = null;
... ...
js/resources/css/AccueilAmda.css
... ... @@ -192,7 +192,6 @@ body{
192 192 font-family: orbitronbold;
193 193 font-size: 16px;
194 194 color: rgba(0, 107, 179, 0.7);
195   - font-weight: bold;
196 195 }
197 196 #userLogin {
198 197 position: relative;
... ... @@ -217,7 +216,6 @@ body{
217 216 font-family: orbitronbold;
218 217 font-size: 16px;
219 218 color: rgba(0, 107, 179, 0.9);
220   - font-weight: bold;
221 219 }
222 220 /* โ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ข ANNOUCEMENTSโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ข*/
223 221 #textAbout {
... ...
js/resources/css/amda.css
... ... @@ -462,10 +462,6 @@ p + p {
462 462 background-image:url( ../images/16x16/plot_page.png ) !important;
463 463 }
464 464  
465   -.icon-plot-pages {
466   - background-image:url( ../images/16x16/plot_pages.png ) !important;
467   -}
468   -
469 465 .icon-plot-layout {
470 466 background-image:url( ../images/16x16/plot_layout.png ) !important;
471 467 }
... ...
js/resources/images/16x16/plot_pages.png deleted

150 Bytes

php/classes/AmdaAction.php
... ... @@ -151,7 +151,6 @@ class AmdaAction
151 151 $isParameter = false;
152 152 $isAddable = false;
153 153 $isSimulation = false;
154   - $plotTabs = FALSE;
155 154 $rank = null;
156 155 $skip = FALSE;
157 156  
... ... @@ -185,19 +184,6 @@ class AmdaAction
185 184 else {
186 185 $info = $id;
187 186 }
188   -
189   - $isLeaf = isset($objplot->tabs);
190   - if ($isLeaf) {
191   - $plotTabs = array();
192   - foreach ($objplot->tabs as $index => $tab) {
193   - $plotTabs[$index] = array(
194   - "name" => (!empty($tab->{'tab-name'})) ? $tab->{'tab-name'} : "Plot ".($index+1),
195   - "id" => $tab->id,
196   - );
197   - }
198   - }
199   - else
200   - $plotTabs = FALSE;
201 187 break;
202 188  
203 189 // case 'alias':
... ... @@ -597,7 +583,7 @@ class AmdaAction
597 583 }
598 584  
599 585 $childrenToReturn[] = array('text' => $name, 'id' => $id, 'nodeType' => $nodeType, 'info' => $info,
600   - 'help' => $help, 'leaf' => $isLeaf, 'isParameter' => $isParameter, 'dim_1' => $dim_1, 'dim_2' => $dim_2, 'tabs' => $plotTabs,
  586 + 'help' => $help, 'leaf' => $isLeaf, 'isParameter' => $isParameter, 'dim_1' => $dim_1, 'dim_2' => $dim_2,
601 587 'component_info' => isset($component_info) ? $component_info : NULL,
602 588 'iconCls' => isset($iconCls) ? $iconCls : NULL );
603 589 }
... ... @@ -826,7 +812,6 @@ class AmdaAction
826 812 break;
827 813 case 'condition' :
828 814 case 'request' :
829   - case 'plottab' :
830 815 $objectMgr = new RequestMgr($obj->nodeType);
831 816 break;
832 817 case 'alias' :
... ... @@ -916,7 +901,6 @@ class AmdaAction
916 901 break;
917 902 case 'condition' :
918 903 case 'request' :
919   - case 'plottab' :
920 904 $objectMgr = new RequestMgr($obj->nodeType);
921 905 break;
922 906 default:
... ... @@ -1437,11 +1421,10 @@ class AmdaAction
1437 1421 return array('success' => true);
1438 1422 }
1439 1423  
1440   - public function interactivePlot($obj, $multiPlotState)
  1424 + public function interactivePlot($obj)
1441 1425 {
1442 1426 $inputobj = (Object)array(
1443 1427 'action' => $obj,
1444   - 'multiPlotState' => $multiPlotState
1445 1428 );
1446 1429 return $this->executeRequest($inputobj, FunctionTypeEnumClass::ACTION);
1447 1430 }
... ...
php/classes/RequestMgr.php
... ... @@ -30,7 +30,7 @@ class RequestMgr extends AmdaObjectMgr
30 30 $this->attributes = array('name' => '');
31 31 $this->optionalAttributes = array();
32 32  
33   - if ($type == 'request' || $type == 'plottab')
  33 + if ($type == 'request' )
34 34 {
35 35 $this->id_prefix = 'req_';
36 36 }
... ... @@ -73,47 +73,11 @@ class RequestMgr extends AmdaObjectMgr
73 73  
74 74 public function validNameObject($p)
75 75 {
76   - if ($this->type == 'plottab') {
77   - if (empty($p->name)) {
78   - return array('valid' => false, 'error' => 'Name is required');
79   - }
80   - return array('valid' => true);
81   - }
82 76 return parent::validNameObject($p);
83 77 }
84 78  
85 79 public function renameObject($p)
86 80 {
87   - if ($this->type == 'plottab') {
88   - //Rename a plot tab
89   - if (!isset($p->parent) || empty($p->parent)) {
90   - return array('error' => 'Missing parent definition');
91   - }
92   - $plotObj = $this->getObject($p->parent);
93   - if (is_array($plotObj) && isset($plotObj['error'])) {
94   - return array('error' => $plotObj['error']);
95   - }
96   - if (!isset($plotObj->tabs)) {
97   - return array('error' => 'Cannot retrieve tab in plot request');
98   - }
99   - $renameOK = FALSE;
100   - foreach ($plotObj->tabs as &$tab) {
101   - if ($tab->id == $p->id) {
102   - $tab->{'tab-name'} = $p->name;
103   - $renameOK = TRUE;
104   - break;
105   - }
106   - }
107   - if (!$renameOK) {
108   - return array('error' => 'Cannot retrieve tab in plot request 2');
109   - }
110   - //Save modification
111   - $file = fopen(USERREQDIR.$p->parent, 'w');
112   - fwrite($file, json_encode($plotObj));
113   - fclose($file);
114   -
115   - return array('id' => $p->id);
116   - }
117 81 return parent::renameObject($p);
118 82 }
119 83  
... ... @@ -225,17 +189,6 @@ class RequestMgr extends AmdaObjectMgr
225 189 }
226 190  
227 191 $additional = array();
228   - if ($this->type == 'request') {
229   - $additional['tabs'] = array();
230   - if (isset($p->tabs)) {
231   - foreach ($p->tabs as $index => $tab) {
232   - $additional['tabs'][$index] = array(
233   - "name" => (!empty($tab->{'tab-name'})) ? $tab->{'tab-name'} : "Plot ".($index+1),
234   - "id" => $tab->id,
235   - );
236   - }
237   - }
238   - }
239 192  
240 193 $this->descFileName = USERREQDIR.$this->id;
241 194 $p->id = $this->id;
... ... @@ -258,17 +211,12 @@ class RequestMgr extends AmdaObjectMgr
258 211 switch ($obj->nodeType)
259 212 {
260 213 case 'request' :
261   - foreach ($obj->tabs as $tab)
262   - {
263   - $timesrc = $tab->{'multi-plot-linked'} ? $obj->timesrc : $tab->timesrc;
264   -
  214 +
265 215 //TODO check TT as well (first start and last stop ?)
266   - if ($timesrc != 'Interval') continue;
267   - // select active tab
268   - if (!$tab->{'multi-plot-linked'} && $tab->id != $obj->{'last-plotted-tab'}) continue;
  216 + if ($obj->timesrc != 'Interval') continue;
269 217  
270 218 $argsTab = array();
271   - foreach ($tab->panels as $panel)
  219 + foreach ($obj->panels as $panel)
272 220 {
273 221 $params = array();
274 222 foreach ($panel->params as $param)
... ... @@ -283,12 +231,11 @@ class RequestMgr extends AmdaObjectMgr
283 231 if (count($params) > 0)
284 232 {
285 233 $argsTab['param'] = array_unique($params);
286   - $argsTab['startTime'] = $tab->{'multi-plot-linked'} ? $obj->startDate : $tab->startDate;
287   - $argsTab['stopTime'] = $tab->{'multi-plot-linked'} ? $obj->stopDate : $tab->stopDate;
  234 + $argsTab['startTime'] = $obj->startDate;
  235 + $argsTab['stopTime'] = $$obj->stopDate;
288 236 }
289 237 }
290 238 if (count($argsTab) > 0) $args[] = $argsTab;
291   - }
292 239 break;
293 240 case 'condition' :
294 241 //$argsTab = array();
... ...
php/classes/UserMgr.php
... ... @@ -517,6 +517,13 @@ class UserMgr
517 517 $this->isFirst = true;
518 518 }
519 519  
  520 + $requestManager = new RequestManagerClass();
  521 + try {
  522 + $res = $requestManager->runIHMRequest($this->user, $this->getIPclient(), FunctionTypeEnumClass::USERWSINIT, array());
  523 + } catch (Exception $e) {
  524 + die("Login for ".$this->user." failed: Error in WS dirs - ".$e->getMessage());
  525 + }
  526 +
520 527 if (file_exists($this->userdir.'newLogin')) {
521 528 touch($this->userdir.'lastLogin', filemtime($this->userdir.'newLogin'));
522 529 }
... ...
php/classes/simple_html_dom.php
1   -<?php
2   -/*******************************************************************************
3   -Version: 1.11 ($Rev: 175 $)
4   -Website: http://sourceforge.net/projects/simplehtmldom/
5   -Author: S.C. Chen <me578022@gmail.com>
6   -Acknowledge: Jose Solorzano (https://sourceforge.net/projects/php-html/)
7   -Contributions by:
8   - Yousuke Kumakura (Attribute filters)
9   - Vadim Voituk (Negative indexes supports of "find" method)
10   - Antcs (Constructor with automatically load contents either text or file/url)
11   -Licensed under The MIT License
12   -Redistributions of files must retain the above copyright notice.
13   -*******************************************************************************/
14   -
15   -define('HDOM_TYPE_ELEMENT', 1);
16   -define('HDOM_TYPE_COMMENT', 2);
17   -define('HDOM_TYPE_TEXT', 3);
18   -define('HDOM_TYPE_ENDTAG', 4);
19   -define('HDOM_TYPE_ROOT', 5);
20   -define('HDOM_TYPE_UNKNOWN', 6);
21   -define('HDOM_QUOTE_DOUBLE', 0);
22   -define('HDOM_QUOTE_SINGLE', 1);
23   -define('HDOM_QUOTE_NO', 3);
24   -define('HDOM_INFO_BEGIN', 0);
25   -define('HDOM_INFO_END', 1);
26   -define('HDOM_INFO_QUOTE', 2);
27   -define('HDOM_INFO_SPACE', 3);
28   -define('HDOM_INFO_TEXT', 4);
29   -define('HDOM_INFO_INNER', 5);
30   -define('HDOM_INFO_OUTER', 6);
31   -define('HDOM_INFO_ENDSPACE',7);
32   -
33   -// helper functions
34   -// -----------------------------------------------------------------------------
35   -// get html dom form file
36   -function file_get_html() {
37   - $dom = new simple_html_dom;
38   - $args = func_get_args();
39   - $dom->load(call_user_func_array('file_get_contents', $args), true);
40   - return $dom;
41   -}
42   -
43   -// get html dom form string
44   -function str_get_html($str, $lowercase=true) {
45   - $dom = new simple_html_dom;
46   - $dom->load($str, $lowercase);
47   - return $dom;
48   -}
49   -
50   -// dump html dom tree
51   -function dump_html_tree($node, $show_attr=true, $deep=0) {
52   - $lead = str_repeat(' ', $deep);
53   - echo $lead.$node->tag;
54   - if ($show_attr && count($node->attr)>0) {
55   - echo '(';
56   - foreach($node->attr as $k=>$v)
57   - echo "[$k]=>\"".$node->$k.'", ';
58   - echo ')';
59   - }
60   - echo "\n";
61   -
62   - foreach($node->nodes as $c)
63   - dump_html_tree($c, $show_attr, $deep+1);
64   -}
65   -
66   -// get dom form file (deprecated)
67   -function file_get_dom() {
68   - $dom = new simple_html_dom;
69   - $args = func_get_args();
70   - $dom->load(call_user_func_array('file_get_contents', $args), true);
71   - return $dom;
72   -}
73   -
74   -// get dom form string (deprecated)
75   -function str_get_dom($str, $lowercase=true) {
76   - $dom = new simple_html_dom;
77   - $dom->load($str, $lowercase);
78   - return $dom;
79   -}
80   -
81   -// simple html dom node
82   -// -----------------------------------------------------------------------------
83   -class simple_html_dom_node {
84   - public $nodetype = HDOM_TYPE_TEXT;
85   - public $tag = 'text';
86   - public $attr = array();
87   - public $children = array();
88   - public $nodes = array();
89   - public $parent = null;
90   - public $_ = array();
91   - private $dom = null;
92   -
93   - function __construct($dom) {
94   - $this->dom = $dom;
95   - $dom->nodes[] = $this;
96   - }
97   -
98   - function __destruct() {
99   - $this->clear();
100   - }
101   -
102   - function __toString() {
103   - return $this->outertext();
104   - }
105   -
106   - // clean up memory due to php5 circular references memory leak...
107   - function clear() {
108   - $this->dom = null;
109   - $this->nodes = null;
110   - $this->parent = null;
111   - $this->children = null;
112   - }
113   -
114   - // dump node's tree
115   - function dump($show_attr=true) {
116   - dump_html_tree($this, $show_attr);
117   - }
118   -
119   - // returns the parent of node
120   - function parent() {
121   - return $this->parent;
122   - }
123   -
124   - // returns children of node
125   - function children($idx=-1) {
126   - if ($idx===-1) return $this->children;
127   - if (isset($this->children[$idx])) return $this->children[$idx];
128   - return null;
129   - }
130   -
131   - // returns the first child of node
132   - function first_child() {
133   - if (count($this->children)>0) return $this->children[0];
134   - return null;
135   - }
136   -
137   - // returns the last child of node
138   - function last_child() {
139   - if (($count=count($this->children))>0) return $this->children[$count-1];
140   - return null;
141   - }
142   -
143   - // returns the next sibling of node
144   - function next_sibling() {
145   - if ($this->parent===null) return null;
146   - $idx = 0;
147   - $count = count($this->parent->children);
148   - while ($idx<$count && $this!==$this->parent->children[$idx])
149   - ++$idx;
150   - if (++$idx>=$count) return null;
151   - return $this->parent->children[$idx];
152   - }
153   -
154   - // returns the previous sibling of node
155   - function prev_sibling() {
156   - if ($this->parent===null) return null;
157   - $idx = 0;
158   - $count = count($this->parent->children);
159   - while ($idx<$count && $this!==$this->parent->children[$idx])
160   - ++$idx;
161   - if (--$idx<0) return null;
162   - return $this->parent->children[$idx];
163   - }
164   -
165   - // get dom node's inner html
166   - function innertext() {
167   - if (isset($this->_[HDOM_INFO_INNER])) return $this->_[HDOM_INFO_INNER];
168   - if (isset($this->_[HDOM_INFO_TEXT])) return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
169   -
170   - $ret = '';
171   - foreach($this->nodes as $n)
172   - $ret .= $n->outertext();
173   - return $ret;
174   - }
175   -
176   - // get dom node's outer text (with tag)
177   - function outertext() {
178   - if ($this->tag==='root') return $this->innertext();
179   -
180   - // trigger callback
181   - if ($this->dom->callback!==null)
182   - call_user_func_array($this->dom->callback, array($this));
183   -
184   - if (isset($this->_[HDOM_INFO_OUTER])) return $this->_[HDOM_INFO_OUTER];
185   - if (isset($this->_[HDOM_INFO_TEXT])) return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
186   -
187   - // render begin tag
188   - $ret = $this->dom->nodes[$this->_[HDOM_INFO_BEGIN]]->makeup();
189   -
190   - // render inner text
191   - if (isset($this->_[HDOM_INFO_INNER]))
192   - $ret .= $this->_[HDOM_INFO_INNER];
193   - else {
194   - foreach($this->nodes as $n)
195   - $ret .= $n->outertext();
196   - }
197   -
198   - // render end tag
199   - if(isset($this->_[HDOM_INFO_END]) && $this->_[HDOM_INFO_END]!=0)
200   - $ret .= '</'.$this->tag.'>';
201   - return $ret;
202   - }
203   -
204   - // get dom node's plain text
205   - function text() {
206   - if (isset($this->_[HDOM_INFO_INNER])) return $this->_[HDOM_INFO_INNER];
207   - switch ($this->nodetype) {
208   - case HDOM_TYPE_TEXT: return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
209   - case HDOM_TYPE_COMMENT: return '';
210   - case HDOM_TYPE_UNKNOWN: return '';
211   - }
212   - if (strcasecmp($this->tag, 'script')===0) return '';
213   - if (strcasecmp($this->tag, 'style')===0) return '';
214   -
215   - $ret = '';
216   - foreach($this->nodes as $n)
217   - $ret .= $n->text();
218   - return $ret;
219   - }
220   -
221   - function xmltext() {
222   - $ret = $this->innertext();
223   - $ret = str_ireplace('<![CDATA[', '', $ret);
224   - $ret = str_replace(']]>', '', $ret);
225   - return $ret;
226   - }
227   -
228   - // build node's text with tag
229   - function makeup() {
230   - // text, comment, unknown
231   - if (isset($this->_[HDOM_INFO_TEXT])) return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
232   -
233   - $ret = '<'.$this->tag;
234   - $i = -1;
235   -
236   - foreach($this->attr as $key=>$val) {
237   - ++$i;
238   -
239   - // skip removed attribute
240   - if ($val===null || $val===false)
241   - continue;
242   -
243   - $ret .= $this->_[HDOM_INFO_SPACE][$i][0];
244   - //no value attr: nowrap, checked selected...
245   - if ($val===true)
246   - $ret .= $key;
247   - else {
248   - switch($this->_[HDOM_INFO_QUOTE][$i]) {
249   - case HDOM_QUOTE_DOUBLE: $quote = '"'; break;
250   - case HDOM_QUOTE_SINGLE: $quote = '\''; break;
251   - default: $quote = '';
252   - }
253   - $ret .= $key.$this->_[HDOM_INFO_SPACE][$i][1].'='.$this->_[HDOM_INFO_SPACE][$i][2].$quote.$val.$quote;
254   - }
255   - }
256   - $ret = $this->dom->restore_noise($ret);
257   - return $ret . $this->_[HDOM_INFO_ENDSPACE] . '>';
258   - }
259   -
260   - // find elements by css selector
261   - function find($selector, $idx=null) {
262   - $selectors = $this->parse_selector($selector);
263   - if (($count=count($selectors))===0) return array();
264   - $found_keys = array();
265   -
266   - // find each selector
267   - for ($c=0; $c<$count; ++$c) {
268   - if (($levle=count($selectors[0]))===0) return array();
269   - if (!isset($this->_[HDOM_INFO_BEGIN])) return array();
270   -
271   - $head = array($this->_[HDOM_INFO_BEGIN]=>1);
272   -
273   - // handle descendant selectors, no recursive!
274   - for ($l=0; $l<$levle; ++$l) {
275   - $ret = array();
276   - foreach($head as $k=>$v) {
277   - $n = ($k===-1) ? $this->dom->root : $this->dom->nodes[$k];
278   - $n->seek($selectors[$c][$l], $ret);
279   - }
280   - $head = $ret;
281   - }
282   -
283   - foreach($head as $k=>$v) {
284   - if (!isset($found_keys[$k]))
285   - $found_keys[$k] = 1;
286   - }
287   - }
288   -
289   - // sort keys
290   - ksort($found_keys);
291   -
292   - $found = array();
293   - foreach($found_keys as $k=>$v)
294   - $found[] = $this->dom->nodes[$k];
295   -
296   - // return nth-element or array
297   - if (is_null($idx)) return $found;
298   - else if ($idx<0) $idx = count($found) + $idx;
299   - return (isset($found[$idx])) ? $found[$idx] : null;
300   - }
301   -
302   - // seek for given conditions
303   - protected function seek($selector, &$ret) {
304   - list($tag, $key, $val, $exp, $no_key) = $selector;
305   -
306   - // xpath index
307   - if ($tag && $key && is_numeric($key)) {
308   - $count = 0;
309   - foreach ($this->children as $c) {
310   - if ($tag==='*' || $tag===$c->tag) {
311   - if (++$count==$key) {
312   - $ret[$c->_[HDOM_INFO_BEGIN]] = 1;
313   - return;
314   - }
315   - }
316   - }
317   - return;
318   - }
319   -
320   - $end = (!empty($this->_[HDOM_INFO_END])) ? $this->_[HDOM_INFO_END] : 0;
321   - if ($end==0) {
322   - $parent = $this->parent;
323   - while (!isset($parent->_[HDOM_INFO_END]) && $parent!==null) {
324   - $end -= 1;
325   - $parent = $parent->parent;
326   - }
327   - $end += $parent->_[HDOM_INFO_END];
328   - }
329   -
330   - for($i=$this->_[HDOM_INFO_BEGIN]+1; $i<$end; ++$i) {
331   - $node = $this->dom->nodes[$i];
332   - $pass = true;
333   -
334   - if ($tag==='*' && !$key) {
335   - if (in_array($node, $this->children, true))
336   - $ret[$i] = 1;
337   - continue;
338   - }
339   -
340   - // compare tag
341   - if ($tag && $tag!=$node->tag && $tag!=='*') {$pass=false;}
342   - // compare key
343   - if ($pass && $key) {
344   - if ($no_key) {
345   - if (isset($node->attr[$key])) $pass=false;
346   - }
347   - else if (!isset($node->attr[$key])) $pass=false;
348   - }
349   - // compare value
350   - if ($pass && $key && $val && $val!=='*') {
351   - $check = $this->match($exp, $val, $node->attr[$key]);
352   - // handle multiple class
353   - if (!$check && strcasecmp($key, 'class')===0) {
354   - foreach(explode(' ',$node->attr[$key]) as $k) {
355   - $check = $this->match($exp, $val, $k);
356   - if ($check) break;
357   - }
358   - }
359   - if (!$check) $pass = false;
360   - }
361   - if ($pass) $ret[$i] = 1;
362   - unset($node);
363   - }
364   - }
365   -
366   - protected function match($exp, $pattern, $value) {
367   - switch ($exp) {
368   - case '=':
369   - return ($value===$pattern);
370   - case '!=':
371   - return ($value!==$pattern);
372   - case '^=':
373   - return preg_match("/^".preg_quote($pattern,'/')."/", $value);
374   - case '$=':
375   - return preg_match("/".preg_quote($pattern,'/')."$/", $value);
376   - case '*=':
377   - if ($pattern[0]=='/')
378   - return preg_match($pattern, $value);
379   - return preg_match("/".$pattern."/i", $value);
380   - }
381   - return false;
382   - }
383   -
384   - protected function parse_selector($selector_string) {
385   - // pattern of CSS selectors, modified from mootools
386   - $pattern = "/([\w-:\*]*)(?:\#([\w-]+)|\.([\w-]+))?(?:\[@?(!?[\w-]+)(?:([!*^$]?=)[\"']?(.*?)[\"']?)?\])?([\/, ]+)/is";
387   - preg_match_all($pattern, trim($selector_string).' ', $matches, PREG_SET_ORDER);
388   - $selectors = array();
389   - $result = array();
390   - //print_r($matches);
391   -
392   - foreach ($matches as $m) {
393   - $m[0] = trim($m[0]);
394   - if ($m[0]==='' || $m[0]==='/' || $m[0]==='//') continue;
395   - // for borwser grnreated xpath
396   - if ($m[1]==='tbody') continue;
397   -
398   - list($tag, $key, $val, $exp, $no_key) = array($m[1], null, null, '=', false);
399   - if(!empty($m[2])) {$key='id'; $val=$m[2];}
400   - if(!empty($m[3])) {$key='class'; $val=$m[3];}
401   - if(!empty($m[4])) {$key=$m[4];}
402   - if(!empty($m[5])) {$exp=$m[5];}
403   - if(!empty($m[6])) {$val=$m[6];}
404   -
405   - // convert to lowercase
406   - if ($this->dom->lowercase) {$tag=strtolower($tag); $key=strtolower($key);}
407   - //elements that do NOT have the specified attribute
408   - if (isset($key[0]) && $key[0]==='!') {$key=substr($key, 1); $no_key=true;}
409   -
410   - $result[] = array($tag, $key, $val, $exp, $no_key);
411   - if (trim($m[7])===',') {
412   - $selectors[] = $result;
413   - $result = array();
414   - }
415   - }
416   - if (count($result)>0)
417   - $selectors[] = $result;
418   - return $selectors;
419   - }
420   -
421   - function __get($name) {
422   - if (isset($this->attr[$name])) return $this->attr[$name];
423   - switch($name) {
424   - case 'outertext': return $this->outertext();
425   - case 'innertext': return $this->innertext();
426   - case 'plaintext': return $this->text();
427   - case 'xmltext': return $this->xmltext();
428   - default: return array_key_exists($name, $this->attr);
429   - }
430   - }
431   -
432   - function __set($name, $value) {
433   - switch($name) {
434   - case 'outertext': return $this->_[HDOM_INFO_OUTER] = $value;
435   - case 'innertext':
436   - if (isset($this->_[HDOM_INFO_TEXT])) return $this->_[HDOM_INFO_TEXT] = $value;
437   - return $this->_[HDOM_INFO_INNER] = $value;
438   - }
439   - if (!isset($this->attr[$name])) {
440   - $this->_[HDOM_INFO_SPACE][] = array(' ', '', '');
441   - $this->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_DOUBLE;
442   - }
443   - $this->attr[$name] = $value;
444   - }
445   -
446   - function __isset($name) {
447   - switch($name) {
448   - case 'outertext': return true;
449   - case 'innertext': return true;
450   - case 'plaintext': return true;
451   - }
452   - //no value attr: nowrap, checked selected...
453   - return (array_key_exists($name, $this->attr)) ? true : isset($this->attr[$name]);
454   - }
455   -
456   - function __unset($name) {
457   - if (isset($this->attr[$name]))
458   - unset($this->attr[$name]);
459   - }
460   -
461   - // camel naming conventions
462   - function getAllAttributes() {return $this->attr;}
463   - function getAttribute($name) {return $this->__get($name);}
464   - function setAttribute($name, $value) {$this->__set($name, $value);}
465   - function hasAttribute($name) {return $this->__isset($name);}
466   - function removeAttribute($name) {$this->__set($name, null);}
467   - function getElementById($id) {return $this->find("#$id", 0);}
468   - function getElementsById($id, $idx=null) {return $this->find("#$id", $idx);}
469   - function getElementByTagName($name) {return $this->find($name, 0);}
470   - function getElementsByTagName($name, $idx=null) {return $this->find($name, $idx);}
471   - function parentNode() {return $this->parent();}
472   - function childNodes($idx=-1) {return $this->children($idx);}
473   - function firstChild() {return $this->first_child();}
474   - function lastChild() {return $this->last_child();}
475   - function nextSibling() {return $this->next_sibling();}
476   - function previousSibling() {return $this->prev_sibling();}
477   -}
478   -
479   -// simple html dom parser
480   -// -----------------------------------------------------------------------------
481   -class simple_html_dom {
482   - public $root = null;
483   - public $nodes = array();
484   - public $callback = null;
485   - public $lowercase = false;
486   - protected $pos;
487   - protected $doc;
488   - protected $char;
489   - protected $size;
490   - protected $cursor;
491   - protected $parent;
492   - protected $noise = array();
493   - protected $token_blank = " \t\r\n";
494   - protected $token_equal = ' =/>';
495   - protected $token_slash = " />\r\n\t";
496   - protected $token_attr = ' >';
497   - // use isset instead of in_array, performance boost about 30%...
498   - protected $self_closing_tags = array('img'=>1, 'br'=>1, 'input'=>1, 'meta'=>1, 'link'=>1, 'hr'=>1, 'base'=>1, 'embed'=>1, 'spacer'=>1);
499   - protected $block_tags = array('root'=>1, 'body'=>1, 'form'=>1, 'div'=>1, 'span'=>1, 'table'=>1);
500   - protected $optional_closing_tags = array(
501   - 'tr'=>array('tr'=>1, 'td'=>1, 'th'=>1),
502   - 'th'=>array('th'=>1),
503   - 'td'=>array('td'=>1),
504   - 'li'=>array('li'=>1),
505   - 'dt'=>array('dt'=>1, 'dd'=>1),
506   - 'dd'=>array('dd'=>1, 'dt'=>1),
507   - 'dl'=>array('dd'=>1, 'dt'=>1),
508   - 'p'=>array('p'=>1),
509   - 'nobr'=>array('nobr'=>1),
510   - );
511   -
512   - function __construct($str=null) {
513   - if ($str) {
514   - if (preg_match("/^http:\/\//i",$str) || is_file($str))
515   - $this->load_file($str);
516   - else
517   - $this->load($str);
518   - }
519   - }
520   -
521   - function __destruct() {
522   - $this->clear();
523   - }
524   -
525   - // load html from string
526   - function load($str, $lowercase=true) {
527   - // prepare
528   - $this->prepare($str, $lowercase);
529   - // strip out comments
530   - $this->remove_noise("'<!--(.*?)-->'is");
531   - // strip out cdata
532   - $this->remove_noise("'<!\[CDATA\[(.*?)\]\]>'is", true);
533   - // strip out <style> tags
534   - $this->remove_noise("'<\s*style[^>]*[^/]>(.*?)<\s*/\s*style\s*>'is");
535   - $this->remove_noise("'<\s*style\s*>(.*?)<\s*/\s*style\s*>'is");
536   - // strip out <script> tags
537   - $this->remove_noise("'<\s*script[^>]*[^/]>(.*?)<\s*/\s*script\s*>'is");
538   - $this->remove_noise("'<\s*script\s*>(.*?)<\s*/\s*script\s*>'is");
539   - // strip out preformatted tags
540   - $this->remove_noise("'<\s*(?:code)[^>]*>(.*?)<\s*/\s*(?:code)\s*>'is");
541   - // strip out server side scripts
542   - $this->remove_noise("'(<\?)(.*?)(\?>)'s", true);
543   - // strip smarty scripts
544   - $this->remove_noise("'(\{\w)(.*?)(\})'s", true);
545   -
546   - // parsing
547   - while ($this->parse());
548   - // end
549   - $this->root->_[HDOM_INFO_END] = $this->cursor;
550   - }
551   -
552   - // load html from file
553   - function load_file() {
554   - $args = func_get_args();
555   - $this->load(call_user_func_array('file_get_contents', $args), true);
556   - }
557   -
558   - // set callback function
559   - function set_callback($function_name) {
560   - $this->callback = $function_name;
561   - }
562   -
563   - // remove callback function
564   - function remove_callback() {
565   - $this->callback = null;
566   - }
567   -
568   - // save dom as string
569   - function save($filepath='') {
570   - $ret = $this->root->innertext();
571   - if ($filepath!=='') file_put_contents($filepath, $ret);
572   - return $ret;
573   - }
574   -
575   - // find dom node by css selector
576   - function find($selector, $idx=null) {
577   - return $this->root->find($selector, $idx);
578   - }
579   -
580   - // clean up memory due to php5 circular references memory leak...
581   - function clear() {
582   - foreach($this->nodes as $n) {$n->clear(); $n = null;}
583   - if (isset($this->parent)) {$this->parent->clear(); unset($this->parent);}
584   - if (isset($this->root)) {$this->root->clear(); unset($this->root);}
585   - unset($this->doc);
586   - unset($this->noise);
587   - }
588   -
589   - function dump($show_attr=true) {
590   - $this->root->dump($show_attr);
591   - }
592   -
593   - // prepare HTML data and init everything
594   - protected function prepare($str, $lowercase=true) {
595   - $this->clear();
596   - $this->doc = $str;
597   - $this->pos = 0;
598   - $this->cursor = 1;
599   - $this->noise = array();
600   - $this->nodes = array();
601   - $this->lowercase = $lowercase;
602   - $this->root = new simple_html_dom_node($this);
603   - $this->root->tag = 'root';
604   - $this->root->_[HDOM_INFO_BEGIN] = -1;
605   - $this->root->nodetype = HDOM_TYPE_ROOT;
606   - $this->parent = $this->root;
607   - // set the length of content
608   - $this->size = strlen($str);
609   - if ($this->size>0) $this->char = $this->doc[0];
610   - }
611   -
612   - // parse html content
613   - protected function parse() {
614   - if (($s = $this->copy_until_char('<'))==='')
615   - return $this->read_tag();
616   -
617   - // text
618   - $node = new simple_html_dom_node($this);
619   - ++$this->cursor;
620   - $node->_[HDOM_INFO_TEXT] = $s;
621   - $this->link_nodes($node, false);
622   - return true;
623   - }
624   -
625   - // read tag info
626   - protected function read_tag() {
627   - if ($this->char!=='<') {
628   - $this->root->_[HDOM_INFO_END] = $this->cursor;
629   - return false;
630   - }
631   - $begin_tag_pos = $this->pos;
632   - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
633   -
634   - // end tag
635   - if ($this->char==='/') {
636   - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
637   - $this->skip($this->token_blank_t);
638   - $tag = $this->copy_until_char('>');
639   -
640   - // skip attributes in end tag
641   - if (($pos = strpos($tag, ' '))!==false)
642   - $tag = substr($tag, 0, $pos);
643   -
644   - $parent_lower = strtolower($this->parent->tag);
645   - $tag_lower = strtolower($tag);
646   -
647   - if ($parent_lower!==$tag_lower) {
648   - if (isset($this->optional_closing_tags[$parent_lower]) && isset($this->block_tags[$tag_lower])) {
649   - $this->parent->_[HDOM_INFO_END] = 0;
650   - $org_parent = $this->parent;
651   -
652   - while (($this->parent->parent) && strtolower($this->parent->tag)!==$tag_lower)
653   - $this->parent = $this->parent->parent;
654   -
655   - if (strtolower($this->parent->tag)!==$tag_lower) {
656   - $this->parent = $org_parent; // restore origonal parent
657   - if ($this->parent->parent) $this->parent = $this->parent->parent;
658   - $this->parent->_[HDOM_INFO_END] = $this->cursor;
659   - return $this->as_text_node($tag);
660   - }
661   - }
662   - else if (($this->parent->parent) && isset($this->block_tags[$tag_lower])) {
663   - $this->parent->_[HDOM_INFO_END] = 0;
664   - $org_parent = $this->parent;
665   -
666   - while (($this->parent->parent) && strtolower($this->parent->tag)!==$tag_lower)
667   - $this->parent = $this->parent->parent;
668   -
669   - if (strtolower($this->parent->tag)!==$tag_lower) {
670   - $this->parent = $org_parent; // restore origonal parent
671   - $this->parent->_[HDOM_INFO_END] = $this->cursor;
672   - return $this->as_text_node($tag);
673   - }
674   - }
675   - else if (($this->parent->parent) && strtolower($this->parent->parent->tag)===$tag_lower) {
676   - $this->parent->_[HDOM_INFO_END] = 0;
677   - $this->parent = $this->parent->parent;
678   - }
679   - else
680   - return $this->as_text_node($tag);
681   - }
682   -
683   - $this->parent->_[HDOM_INFO_END] = $this->cursor;
684   - if ($this->parent->parent) $this->parent = $this->parent->parent;
685   -
686   - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
687   - return true;
688   - }
689   -
690   - $node = new simple_html_dom_node($this);
691   - $node->_[HDOM_INFO_BEGIN] = $this->cursor;
692   - ++$this->cursor;
693   - $tag = $this->copy_until($this->token_slash);
694   -
695   - // doctype, cdata & comments...
696   - if (isset($tag[0]) && $tag[0]==='!') {
697   - $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until_char('>');
698   -
699   - if (isset($tag[2]) && $tag[1]==='-' && $tag[2]==='-') {
700   - $node->nodetype = HDOM_TYPE_COMMENT;
701   - $node->tag = 'comment';
702   - } else {
703   - $node->nodetype = HDOM_TYPE_UNKNOWN;
704   - $node->tag = 'unknown';
705   - }
706   -
707   - if ($this->char==='>') $node->_[HDOM_INFO_TEXT].='>';
708   - $this->link_nodes($node, true);
709   - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
710   - return true;
711   - }
712   -
713   - // text
714   - if ($pos=strpos($tag, '<')!==false) {
715   - $tag = '<' . substr($tag, 0, -1);
716   - $node->_[HDOM_INFO_TEXT] = $tag;
717   - $this->link_nodes($node, false);
718   - $this->char = $this->doc[--$this->pos]; // prev
719   - return true;
720   - }
721   -
722   - if (!preg_match("/^[\w-:]+$/", $tag)) {
723   - $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until('<>');
724   - if ($this->char==='<') {
725   - $this->link_nodes($node, false);
726   - return true;
727   - }
728   -
729   - if ($this->char==='>') $node->_[HDOM_INFO_TEXT].='>';
730   - $this->link_nodes($node, false);
731   - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
732   - return true;
733   - }
734   -
735   - // begin tag
736   - $node->nodetype = HDOM_TYPE_ELEMENT;
737   - $tag_lower = strtolower($tag);
738   - $node->tag = ($this->lowercase) ? $tag_lower : $tag;
739   -
740   - // handle optional closing tags
741   - if (isset($this->optional_closing_tags[$tag_lower]) ) {
742   - while (isset($this->optional_closing_tags[$tag_lower][strtolower($this->parent->tag)])) {
743   - $this->parent->_[HDOM_INFO_END] = 0;
744   - $this->parent = $this->parent->parent;
745   - }
746   - $node->parent = $this->parent;
747   - }
748   -
749   - $guard = 0; // prevent infinity loop
750   - $space = array($this->copy_skip($this->token_blank), '', '');
751   -
752   - // attributes
753   - do {
754   - if ($this->char!==null && $space[0]==='') break;
755   - $name = $this->copy_until($this->token_equal);
756   - if($guard===$this->pos) {
757   - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
758   - continue;
759   - }
760   - $guard = $this->pos;
761   -
762   - // handle endless '<'
763   - if($this->pos>=$this->size-1 && $this->char!=='>') {
764   - $node->nodetype = HDOM_TYPE_TEXT;
765   - $node->_[HDOM_INFO_END] = 0;
766   - $node->_[HDOM_INFO_TEXT] = '<'.$tag . $space[0] . $name;
767   - $node->tag = 'text';
768   - $this->link_nodes($node, false);
769   - return true;
770   - }
771   -
772   - // handle mismatch '<'
773   - if($this->doc[$this->pos-1]=='<') {
774   - $node->nodetype = HDOM_TYPE_TEXT;
775   - $node->tag = 'text';
776   - $node->attr = array();
777   - $node->_[HDOM_INFO_END] = 0;
778   - $node->_[HDOM_INFO_TEXT] = substr($this->doc, $begin_tag_pos, $this->pos-$begin_tag_pos-1);
779   - $this->pos -= 2;
780   - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
781   - $this->link_nodes($node, false);
782   - return true;
783   - }
784   -
785   - if ($name!=='/' && $name!=='') {
786   - $space[1] = $this->copy_skip($this->token_blank);
787   - $name = $this->restore_noise($name);
788   - if ($this->lowercase) $name = strtolower($name);
789   - if ($this->char==='=') {
790   - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
791   - $this->parse_attr($node, $name, $space);
792   - }
793   - else {
794   - //no value attr: nowrap, checked selected...
795   - $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_NO;
796   - $node->attr[$name] = true;
797   - if ($this->char!='>') $this->char = $this->doc[--$this->pos]; // prev
798   - }
799   - $node->_[HDOM_INFO_SPACE][] = $space;
800   - $space = array($this->copy_skip($this->token_blank), '', '');
801   - }
802   - else
803   - break;
804   - } while($this->char!=='>' && $this->char!=='/');
805   -
806   - $this->link_nodes($node, true);
807   - $node->_[HDOM_INFO_ENDSPACE] = $space[0];
808   -
809   - // check self closing
810   - if ($this->copy_until_char_escape('>')==='/') {
811   - $node->_[HDOM_INFO_ENDSPACE] .= '/';
812   - $node->_[HDOM_INFO_END] = 0;
813   - }
814   - else {
815   - // reset parent
816   - if (!isset($this->self_closing_tags[strtolower($node->tag)])) $this->parent = $node;
817   - }
818   - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
819   - return true;
820   - }
821   -
822   - // parse attributes
823   - protected function parse_attr($node, $name, &$space) {
824   - $space[2] = $this->copy_skip($this->token_blank);
825   - switch($this->char) {
826   - case '"':
827   - $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_DOUBLE;
828   - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
829   - $node->attr[$name] = $this->restore_noise($this->copy_until_char_escape('"'));
830   - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
831   - break;
832   - case '\'':
833   - $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_SINGLE;
834   - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
835   - $node->attr[$name] = $this->restore_noise($this->copy_until_char_escape('\''));
836   - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
837   - break;
838   - default:
839   - $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_NO;
840   - $node->attr[$name] = $this->restore_noise($this->copy_until($this->token_attr));
841   - }
842   - }
843   -
844   - // link node's parent
845   - protected function link_nodes(&$node, $is_child) {
846   - $node->parent = $this->parent;
847   - $this->parent->nodes[] = $node;
848   - if ($is_child)
849   - $this->parent->children[] = $node;
850   - }
851   -
852   - // as a text node
853   - protected function as_text_node($tag) {
854   - $node = new simple_html_dom_node($this);
855   - ++$this->cursor;
856   - $node->_[HDOM_INFO_TEXT] = '</' . $tag . '>';
857   - $this->link_nodes($node, false);
858   - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
859   - return true;
860   - }
861   -
862   - protected function skip($chars) {
863   - $this->pos += strspn($this->doc, $chars, $this->pos);
864   - $this->char = ($this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
865   - }
866   -
867   - protected function copy_skip($chars) {
868   - $pos = $this->pos;
869   - $len = strspn($this->doc, $chars, $pos);
870   - $this->pos += $len;
871   - $this->char = ($this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
872   - if ($len===0) return '';
873   - return substr($this->doc, $pos, $len);
874   - }
875   -
876   - protected function copy_until($chars) {
877   - $pos = $this->pos;
878   - $len = strcspn($this->doc, $chars, $pos);
879   - $this->pos += $len;
880   - $this->char = ($this->pos<$this->size) ? $this->doc[$this->pos] : null; // next
881   - return substr($this->doc, $pos, $len);
882   - }
883   -
884   - protected function copy_until_char($char) {
885   - if ($this->char===null) return '';
886   -
887   - if (($pos = strpos($this->doc, $char, $this->pos))===false) {
888   - $ret = substr($this->doc, $this->pos, $this->size-$this->pos);
889   - $this->char = null;
890   - $this->pos = $this->size;
891   - return $ret;
892   - }
893   -
894   - if ($pos===$this->pos) return '';
895   - $pos_old = $this->pos;
896   - $this->char = $this->doc[$pos];
897   - $this->pos = $pos;
898   - return substr($this->doc, $pos_old, $pos-$pos_old);
899   - }
900   -
901   - protected function copy_until_char_escape($char) {
902   - if ($this->char===null) return '';
903   -
904   - $start = $this->pos;
905   - while(1) {
906   - if (($pos = strpos($this->doc, $char, $start))===false) {
907   - $ret = substr($this->doc, $this->pos, $this->size-$this->pos);
908   - $this->char = null;
909   - $this->pos = $this->size;
910   - return $ret;
911   - }
912   -
913   - if ($pos===$this->pos) return '';
914   -
915   - if ($this->doc[$pos-1]==='\\') {
916   - $start = $pos+1;
917   - continue;
918   - }
919   -
920   - $pos_old = $this->pos;
921   - $this->char = $this->doc[$pos];
922   - $this->pos = $pos;
923   - return substr($this->doc, $pos_old, $pos-$pos_old);
924   - }
925   - }
926   -
927   - // remove noise from html content
928   - protected function remove_noise($pattern, $remove_tag=false) {
929   - $count = preg_match_all($pattern, $this->doc, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
930   -
931   - for ($i=$count-1; $i>-1; --$i) {
932   - $key = '___noise___'.sprintf('% 3d', count($this->noise)+100);
933   - $idx = ($remove_tag) ? 0 : 1;
934   - $this->noise[$key] = $matches[$i][$idx][0];
935   - $this->doc = substr_replace($this->doc, $key, $matches[$i][$idx][1], strlen($matches[$i][$idx][0]));
936   - }
937   -
938   - // reset the length of content
939   - $this->size = strlen($this->doc);
940   - if ($this->size>0) $this->char = $this->doc[0];
941   - }
942   -
943   - // restore noise to html content
944   - function restore_noise($text) {
945   - while(($pos=strpos($text, '___noise___'))!==false) {
946   - $key = '___noise___'.$text[$pos+11].$text[$pos+12].$text[$pos+13];
947   - if (isset($this->noise[$key]))
948   - $text = substr($text, 0, $pos).$this->noise[$key].substr($text, $pos+14);
949   - }
950   - return $text;
951   - }
952   -
953   - function __toString() {
954   - return $this->root->innertext();
955   - }
956   -
957   - function __get($name) {
958   - switch($name) {
959   - case 'outertext': return $this->root->innertext();
960   - case 'innertext': return $this->root->innertext();
961   - case 'plaintext': return $this->root->text();
962   - }
963   - }
964   -
965   - // camel naming conventions
966   - function childNodes($idx=-1) {return $this->root->childNodes($idx);}
967   - function firstChild() {return $this->root->first_child();}
968   - function lastChild() {return $this->root->last_child();}
969   - function getElementById($id) {return $this->find("#$id", 0);}
970   - function getElementsById($id, $idx=null) {return $this->find("#$id", $idx);}
971   - function getElementByTagName($name) {return $this->find($name, 0);}
972   - function getElementsByTagName($name, $idx=-1) {return $this->find($name, $idx);}
973   - function loadFile() {$args = func_get_args();$this->load(call_user_func_array('file_get_contents', $args), true);}
974   -}
975   -?>
976 1 \ No newline at end of file
  2 +<?php
  3 +/**
  4 + * Website: http://sourceforge.net/projects/simplehtmldom/
  5 + * Additional projects: http://sourceforge.net/projects/debugobject/
  6 + * Acknowledge: Jose Solorzano (https://sourceforge.net/projects/php-html/)
  7 + *
  8 + * Licensed under The MIT License
  9 + * See the LICENSE file in the project root for more information.
  10 + *
  11 + * Authors:
  12 + * S.C. Chen
  13 + * John Schlick
  14 + * Rus Carroll
  15 + * logmanoriginal
  16 + *
  17 + * Contributors:
  18 + * Yousuke Kumakura
  19 + * Vadim Voituk
  20 + * Antcs
  21 + *
  22 + * Version Rev. 1.9 (290)
  23 + */
  24 +
  25 +define('HDOM_TYPE_ELEMENT', 1);
  26 +define('HDOM_TYPE_COMMENT', 2);
  27 +define('HDOM_TYPE_TEXT', 3);
  28 +define('HDOM_TYPE_ENDTAG', 4);
  29 +define('HDOM_TYPE_ROOT', 5);
  30 +define('HDOM_TYPE_UNKNOWN', 6);
  31 +define('HDOM_QUOTE_DOUBLE', 0);
  32 +define('HDOM_QUOTE_SINGLE', 1);
  33 +define('HDOM_QUOTE_NO', 3);
  34 +define('HDOM_INFO_BEGIN', 0);
  35 +define('HDOM_INFO_END', 1);
  36 +define('HDOM_INFO_QUOTE', 2);
  37 +define('HDOM_INFO_SPACE', 3);
  38 +define('HDOM_INFO_TEXT', 4);
  39 +define('HDOM_INFO_INNER', 5);
  40 +define('HDOM_INFO_OUTER', 6);
  41 +define('HDOM_INFO_ENDSPACE', 7);
  42 +
  43 +defined('DEFAULT_TARGET_CHARSET') || define('DEFAULT_TARGET_CHARSET', 'UTF-8');
  44 +defined('DEFAULT_BR_TEXT') || define('DEFAULT_BR_TEXT', "\r\n");
  45 +defined('DEFAULT_SPAN_TEXT') || define('DEFAULT_SPAN_TEXT', ' ');
  46 +defined('MAX_FILE_SIZE') || define('MAX_FILE_SIZE', 600000);
  47 +define('HDOM_SMARTY_AS_TEXT', 1);
  48 +
  49 +function file_get_html(
  50 + $url,
  51 + $use_include_path = false,
  52 + $context = null,
  53 + $offset = 0,
  54 + $maxLen = -1,
  55 + $lowercase = true,
  56 + $forceTagsClosed = true,
  57 + $target_charset = DEFAULT_TARGET_CHARSET,
  58 + $stripRN = true,
  59 + $defaultBRText = DEFAULT_BR_TEXT,
  60 + $defaultSpanText = DEFAULT_SPAN_TEXT)
  61 +{
  62 + if($maxLen <= 0) { $maxLen = MAX_FILE_SIZE; }
  63 +
  64 + $dom = new simple_html_dom(
  65 + null,
  66 + $lowercase,
  67 + $forceTagsClosed,
  68 + $target_charset,
  69 + $stripRN,
  70 + $defaultBRText,
  71 + $defaultSpanText
  72 + );
  73 +
  74 + /**
  75 + * For sourceforge users: uncomment the next line and comment the
  76 + * retrieve_url_contents line 2 lines down if it is not already done.
  77 + */
  78 + $contents = file_get_contents(
  79 + $url,
  80 + $use_include_path,
  81 + $context,
  82 + $offset,
  83 + $maxLen
  84 + );
  85 + // $contents = retrieve_url_contents($url);
  86 +
  87 + if (empty($contents) || strlen($contents) > $maxLen) {
  88 + $dom->clear();
  89 + return false;
  90 + }
  91 +
  92 + return $dom->load($contents, $lowercase, $stripRN);
  93 +}
  94 +
  95 +function str_get_html(
  96 + $str,
  97 + $lowercase = true,
  98 + $forceTagsClosed = true,
  99 + $target_charset = DEFAULT_TARGET_CHARSET,
  100 + $stripRN = true,
  101 + $defaultBRText = DEFAULT_BR_TEXT,
  102 + $defaultSpanText = DEFAULT_SPAN_TEXT)
  103 +{
  104 + $dom = new simple_html_dom(
  105 + null,
  106 + $lowercase,
  107 + $forceTagsClosed,
  108 + $target_charset,
  109 + $stripRN,
  110 + $defaultBRText,
  111 + $defaultSpanText
  112 + );
  113 +
  114 + if (empty($str) || strlen($str) > MAX_FILE_SIZE) {
  115 + $dom->clear();
  116 + return false;
  117 + }
  118 +
  119 + return $dom->load($str, $lowercase, $stripRN);
  120 +}
  121 +
  122 +function dump_html_tree($node, $show_attr = true, $deep = 0)
  123 +{
  124 + $node->dump($node);
  125 +}
  126 +
  127 +class simple_html_dom_node
  128 +{
  129 + public $nodetype = HDOM_TYPE_TEXT;
  130 + public $tag = 'text';
  131 + public $attr = array();
  132 + public $children = array();
  133 + public $nodes = array();
  134 + public $parent = null;
  135 + public $_ = array();
  136 + public $tag_start = 0;
  137 + private $dom = null;
  138 +
  139 + function __construct($dom)
  140 + {
  141 + $this->dom = $dom;
  142 + $dom->nodes[] = $this;
  143 + }
  144 +
  145 + function __destruct()
  146 + {
  147 + $this->clear();
  148 + }
  149 +
  150 + function __toString()
  151 + {
  152 + return $this->outertext();
  153 + }
  154 +
  155 + function clear()
  156 + {
  157 + $this->dom = null;
  158 + $this->nodes = null;
  159 + $this->parent = null;
  160 + $this->children = null;
  161 + }
  162 +
  163 + function dump($show_attr = true, $depth = 0)
  164 + {
  165 + echo str_repeat("\t", $depth) . $this->tag;
  166 +
  167 + if ($show_attr && count($this->attr) > 0) {
  168 + echo '(';
  169 + foreach ($this->attr as $k => $v) {
  170 + echo "[$k]=>\"$v\", ";
  171 + }
  172 + echo ')';
  173 + }
  174 +
  175 + echo "\n";
  176 +
  177 + if ($this->nodes) {
  178 + foreach ($this->nodes as $node) {
  179 + $node->dump($show_attr, $depth + 1);
  180 + }
  181 + }
  182 + }
  183 +
  184 + function dump_node($echo = true)
  185 + {
  186 + $string = $this->tag;
  187 +
  188 + if (count($this->attr) > 0) {
  189 + $string .= '(';
  190 + foreach ($this->attr as $k => $v) {
  191 + $string .= "[$k]=>\"$v\", ";
  192 + }
  193 + $string .= ')';
  194 + }
  195 +
  196 + if (count($this->_) > 0) {
  197 + $string .= ' $_ (';
  198 + foreach ($this->_ as $k => $v) {
  199 + if (is_array($v)) {
  200 + $string .= "[$k]=>(";
  201 + foreach ($v as $k2 => $v2) {
  202 + $string .= "[$k2]=>\"$v2\", ";
  203 + }
  204 + $string .= ')';
  205 + } else {
  206 + $string .= "[$k]=>\"$v\", ";
  207 + }
  208 + }
  209 + $string .= ')';
  210 + }
  211 +
  212 + if (isset($this->text)) {
  213 + $string .= " text: ({$this->text})";
  214 + }
  215 +
  216 + $string .= ' HDOM_INNER_INFO: ';
  217 +
  218 + if (isset($node->_[HDOM_INFO_INNER])) {
  219 + $string .= "'" . $node->_[HDOM_INFO_INNER] . "'";
  220 + } else {
  221 + $string .= ' NULL ';
  222 + }
  223 +
  224 + $string .= ' children: ' . count($this->children);
  225 + $string .= ' nodes: ' . count($this->nodes);
  226 + $string .= ' tag_start: ' . $this->tag_start;
  227 + $string .= "\n";
  228 +
  229 + if ($echo) {
  230 + echo $string;
  231 + return;
  232 + } else {
  233 + return $string;
  234 + }
  235 + }
  236 +
  237 + function parent($parent = null)
  238 + {
  239 + // I am SURE that this doesn't work properly.
  240 + // It fails to unset the current node from it's current parents nodes or
  241 + // children list first.
  242 + if ($parent !== null) {
  243 + $this->parent = $parent;
  244 + $this->parent->nodes[] = $this;
  245 + $this->parent->children[] = $this;
  246 + }
  247 +
  248 + return $this->parent;
  249 + }
  250 +
  251 + function has_child()
  252 + {
  253 + return !empty($this->children);
  254 + }
  255 +
  256 + function children($idx = -1)
  257 + {
  258 + if ($idx === -1) {
  259 + return $this->children;
  260 + }
  261 +
  262 + if (isset($this->children[$idx])) {
  263 + return $this->children[$idx];
  264 + }
  265 +
  266 + return null;
  267 + }
  268 +
  269 + function first_child()
  270 + {
  271 + if (count($this->children) > 0) {
  272 + return $this->children[0];
  273 + }
  274 + return null;
  275 + }
  276 +
  277 + function last_child()
  278 + {
  279 + if (count($this->children) > 0) {
  280 + return end($this->children);
  281 + }
  282 + return null;
  283 + }
  284 +
  285 + function next_sibling()
  286 + {
  287 + if ($this->parent === null) {
  288 + return null;
  289 + }
  290 +
  291 + $idx = array_search($this, $this->parent->children, true);
  292 +
  293 + if ($idx !== false && isset($this->parent->children[$idx + 1])) {
  294 + return $this->parent->children[$idx + 1];
  295 + }
  296 +
  297 + return null;
  298 + }
  299 +
  300 + function prev_sibling()
  301 + {
  302 + if ($this->parent === null) {
  303 + return null;
  304 + }
  305 +
  306 + $idx = array_search($this, $this->parent->children, true);
  307 +
  308 + if ($idx !== false && $idx > 0) {
  309 + return $this->parent->children[$idx - 1];
  310 + }
  311 +
  312 + return null;
  313 + }
  314 +
  315 + function find_ancestor_tag($tag)
  316 + {
  317 + global $debug_object;
  318 + if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
  319 +
  320 + if ($this->parent === null) {
  321 + return null;
  322 + }
  323 +
  324 + $ancestor = $this->parent;
  325 +
  326 + while (!is_null($ancestor)) {
  327 + if (is_object($debug_object)) {
  328 + $debug_object->debug_log(2, 'Current tag is: ' . $ancestor->tag);
  329 + }
  330 +
  331 + if ($ancestor->tag === $tag) {
  332 + break;
  333 + }
  334 +
  335 + $ancestor = $ancestor->parent;
  336 + }
  337 +
  338 + return $ancestor;
  339 + }
  340 +
  341 + function innertext()
  342 + {
  343 + if (isset($this->_[HDOM_INFO_INNER])) {
  344 + return $this->_[HDOM_INFO_INNER];
  345 + }
  346 +
  347 + if (isset($this->_[HDOM_INFO_TEXT])) {
  348 + return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
  349 + }
  350 +
  351 + $ret = '';
  352 +
  353 + foreach ($this->nodes as $n) {
  354 + $ret .= $n->outertext();
  355 + }
  356 +
  357 + return $ret;
  358 + }
  359 +
  360 + function outertext()
  361 + {
  362 + global $debug_object;
  363 +
  364 + if (is_object($debug_object)) {
  365 + $text = '';
  366 +
  367 + if ($this->tag === 'text') {
  368 + if (!empty($this->text)) {
  369 + $text = ' with text: ' . $this->text;
  370 + }
  371 + }
  372 +
  373 + $debug_object->debug_log(1, 'Innertext of tag: ' . $this->tag . $text);
  374 + }
  375 +
  376 + if ($this->tag === 'root') {
  377 + return $this->innertext();
  378 + }
  379 +
  380 + // todo: What is the use of this callback? Remove?
  381 + if ($this->dom && $this->dom->callback !== null) {
  382 + call_user_func_array($this->dom->callback, array($this));
  383 + }
  384 +
  385 + if (isset($this->_[HDOM_INFO_OUTER])) {
  386 + return $this->_[HDOM_INFO_OUTER];
  387 + }
  388 +
  389 + if (isset($this->_[HDOM_INFO_TEXT])) {
  390 + return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
  391 + }
  392 +
  393 + $ret = '';
  394 +
  395 + if ($this->dom && $this->dom->nodes[$this->_[HDOM_INFO_BEGIN]]) {
  396 + $ret = $this->dom->nodes[$this->_[HDOM_INFO_BEGIN]]->makeup();
  397 + }
  398 +
  399 + if (isset($this->_[HDOM_INFO_INNER])) {
  400 + // todo: <br> should either never have HDOM_INFO_INNER or always
  401 + if ($this->tag !== 'br') {
  402 + $ret .= $this->_[HDOM_INFO_INNER];
  403 + }
  404 + } elseif ($this->nodes) {
  405 + foreach ($this->nodes as $n) {
  406 + $ret .= $this->convert_text($n->outertext());
  407 + }
  408 + }
  409 +
  410 + if (isset($this->_[HDOM_INFO_END]) && $this->_[HDOM_INFO_END] != 0) {
  411 + $ret .= '</' . $this->tag . '>';
  412 + }
  413 +
  414 + return $ret;
  415 + }
  416 +
  417 + function text()
  418 + {
  419 + if (isset($this->_[HDOM_INFO_INNER])) {
  420 + return $this->_[HDOM_INFO_INNER];
  421 + }
  422 +
  423 + switch ($this->nodetype) {
  424 + case HDOM_TYPE_TEXT: return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
  425 + case HDOM_TYPE_COMMENT: return '';
  426 + case HDOM_TYPE_UNKNOWN: return '';
  427 + }
  428 +
  429 + if (strcasecmp($this->tag, 'script') === 0) { return ''; }
  430 + if (strcasecmp($this->tag, 'style') === 0) { return ''; }
  431 +
  432 + $ret = '';
  433 +
  434 + // In rare cases, (always node type 1 or HDOM_TYPE_ELEMENT - observed
  435 + // for some span tags, and some p tags) $this->nodes is set to NULL.
  436 + // NOTE: This indicates that there is a problem where it's set to NULL
  437 + // without a clear happening.
  438 + // WHY is this happening?
  439 + if (!is_null($this->nodes)) {
  440 + foreach ($this->nodes as $n) {
  441 + // Start paragraph after a blank line
  442 + if ($n->tag === 'p') {
  443 + $ret = trim($ret) . "\n\n";
  444 + }
  445 +
  446 + $ret .= $this->convert_text($n->text());
  447 +
  448 + // If this node is a span... add a space at the end of it so
  449 + // multiple spans don't run into each other. This is plaintext
  450 + // after all.
  451 + if ($n->tag === 'span') {
  452 + $ret .= $this->dom->default_span_text;
  453 + }
  454 + }
  455 + }
  456 + return $ret;
  457 + }
  458 +
  459 + function xmltext()
  460 + {
  461 + $ret = $this->innertext();
  462 + $ret = str_ireplace('<![CDATA[', '', $ret);
  463 + $ret = str_replace(']]>', '', $ret);
  464 + return $ret;
  465 + }
  466 +
  467 + function makeup()
  468 + {
  469 + // text, comment, unknown
  470 + if (isset($this->_[HDOM_INFO_TEXT])) {
  471 + return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]);
  472 + }
  473 +
  474 + $ret = '<' . $this->tag;
  475 + $i = -1;
  476 +
  477 + foreach ($this->attr as $key => $val) {
  478 + ++$i;
  479 +
  480 + // skip removed attribute
  481 + if ($val === null || $val === false) { continue; }
  482 +
  483 + $ret .= $this->_[HDOM_INFO_SPACE][$i][0];
  484 +
  485 + //no value attr: nowrap, checked selected...
  486 + if ($val === true) {
  487 + $ret .= $key;
  488 + } else {
  489 + switch ($this->_[HDOM_INFO_QUOTE][$i])
  490 + {
  491 + case HDOM_QUOTE_DOUBLE: $quote = '"'; break;
  492 + case HDOM_QUOTE_SINGLE: $quote = '\''; break;
  493 + default: $quote = '';
  494 + }
  495 +
  496 + $ret .= $key
  497 + . $this->_[HDOM_INFO_SPACE][$i][1]
  498 + . '='
  499 + . $this->_[HDOM_INFO_SPACE][$i][2]
  500 + . $quote
  501 + . $val
  502 + . $quote;
  503 + }
  504 + }
  505 +
  506 + $ret = $this->dom->restore_noise($ret);
  507 + return $ret . $this->_[HDOM_INFO_ENDSPACE] . '>';
  508 + }
  509 +
  510 + function find($selector, $idx = null, $lowercase = false)
  511 + {
  512 + $selectors = $this->parse_selector($selector);
  513 + if (($count = count($selectors)) === 0) { return array(); }
  514 + $found_keys = array();
  515 +
  516 + // find each selector
  517 + for ($c = 0; $c < $count; ++$c) {
  518 + // The change on the below line was documented on the sourceforge
  519 + // code tracker id 2788009
  520 + // used to be: if (($levle=count($selectors[0]))===0) return array();
  521 + if (($levle = count($selectors[$c])) === 0) { return array(); }
  522 + if (!isset($this->_[HDOM_INFO_BEGIN])) { return array(); }
  523 +
  524 + $head = array($this->_[HDOM_INFO_BEGIN] => 1);
  525 + $cmd = ' '; // Combinator
  526 +
  527 + // handle descendant selectors, no recursive!
  528 + for ($l = 0; $l < $levle; ++$l) {
  529 + $ret = array();
  530 +
  531 + foreach ($head as $k => $v) {
  532 + $n = ($k === -1) ? $this->dom->root : $this->dom->nodes[$k];
  533 + //PaperG - Pass this optional parameter on to the seek function.
  534 + $n->seek($selectors[$c][$l], $ret, $cmd, $lowercase);
  535 + }
  536 +
  537 + $head = $ret;
  538 + $cmd = $selectors[$c][$l][4]; // Next Combinator
  539 + }
  540 +
  541 + foreach ($head as $k => $v) {
  542 + if (!isset($found_keys[$k])) {
  543 + $found_keys[$k] = 1;
  544 + }
  545 + }
  546 + }
  547 +
  548 + // sort keys
  549 + ksort($found_keys);
  550 +
  551 + $found = array();
  552 + foreach ($found_keys as $k => $v) {
  553 + $found[] = $this->dom->nodes[$k];
  554 + }
  555 +
  556 + // return nth-element or array
  557 + if (is_null($idx)) { return $found; }
  558 + elseif ($idx < 0) { $idx = count($found) + $idx; }
  559 + return (isset($found[$idx])) ? $found[$idx] : null;
  560 + }
  561 +
  562 + protected function seek($selector, &$ret, $parent_cmd, $lowercase = false)
  563 + {
  564 + global $debug_object;
  565 + if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
  566 +
  567 + list($tag, $id, $class, $attributes, $cmb) = $selector;
  568 + $nodes = array();
  569 +
  570 + if ($parent_cmd === ' ') { // Descendant Combinator
  571 + // Find parent closing tag if the current element doesn't have a closing
  572 + // tag (i.e. void element)
  573 + $end = (!empty($this->_[HDOM_INFO_END])) ? $this->_[HDOM_INFO_END] : 0;
  574 + if ($end == 0) {
  575 + $parent = $this->parent;
  576 + while (!isset($parent->_[HDOM_INFO_END]) && $parent !== null) {
  577 + $end -= 1;
  578 + $parent = $parent->parent;
  579 + }
  580 + $end += $parent->_[HDOM_INFO_END];
  581 + }
  582 +
  583 + // Get list of target nodes
  584 + $nodes_start = $this->_[HDOM_INFO_BEGIN] + 1;
  585 + $nodes_count = $end - $nodes_start;
  586 + $nodes = array_slice($this->dom->nodes, $nodes_start, $nodes_count, true);
  587 + } elseif ($parent_cmd === '>') { // Child Combinator
  588 + $nodes = $this->children;
  589 + } elseif ($parent_cmd === '+'
  590 + && $this->parent
  591 + && in_array($this, $this->parent->children)) { // Next-Sibling Combinator
  592 + $index = array_search($this, $this->parent->children, true) + 1;
  593 + if ($index < count($this->parent->children))
  594 + $nodes[] = $this->parent->children[$index];
  595 + } elseif ($parent_cmd === '~'
  596 + && $this->parent
  597 + && in_array($this, $this->parent->children)) { // Subsequent Sibling Combinator
  598 + $index = array_search($this, $this->parent->children, true);
  599 + $nodes = array_slice($this->parent->children, $index);
  600 + }
  601 +
  602 + // Go throgh each element starting at this element until the end tag
  603 + // Note: If this element is a void tag, any previous void element is
  604 + // skipped.
  605 + foreach($nodes as $node) {
  606 + $pass = true;
  607 +
  608 + // Skip root nodes
  609 + if(!$node->parent) {
  610 + $pass = false;
  611 + }
  612 +
  613 + // Skip if node isn't a child node (i.e. text nodes)
  614 + if($pass && !in_array($node, $node->parent->children, true)) {
  615 + $pass = false;
  616 + }
  617 +
  618 + // Skip if tag doesn't match
  619 + if ($pass && $tag !== '' && $tag !== $node->tag && $tag !== '*') {
  620 + $pass = false;
  621 + }
  622 +
  623 + // Skip if ID doesn't exist
  624 + if ($pass && $id !== '' && !isset($node->attr['id'])) {
  625 + $pass = false;
  626 + }
  627 +
  628 + // Check if ID matches
  629 + if ($pass && $id !== '' && isset($node->attr['id'])) {
  630 + // Note: Only consider the first ID (as browsers do)
  631 + $node_id = explode(' ', trim($node->attr['id']))[0];
  632 +
  633 + if($id !== $node_id) { $pass = false; }
  634 + }
  635 +
  636 + // Check if all class(es) exist
  637 + if ($pass && $class !== '' && is_array($class) && !empty($class)) {
  638 + if (isset($node->attr['class'])) {
  639 + $node_classes = explode(' ', $node->attr['class']);
  640 +
  641 + if ($lowercase) {
  642 + $node_classes = array_map('strtolower', $node_classes);
  643 + }
  644 +
  645 + foreach($class as $c) {
  646 + if(!in_array($c, $node_classes)) {
  647 + $pass = false;
  648 + break;
  649 + }
  650 + }
  651 + } else {
  652 + $pass = false;
  653 + }
  654 + }
  655 +
  656 + // Check attributes
  657 + if ($pass
  658 + && $attributes !== ''
  659 + && is_array($attributes)
  660 + && !empty($attributes)) {
  661 + foreach($attributes as $a) {
  662 + list (
  663 + $att_name,
  664 + $att_expr,
  665 + $att_val,
  666 + $att_inv,
  667 + $att_case_sensitivity
  668 + ) = $a;
  669 +
  670 + // Handle indexing attributes (i.e. "[2]")
  671 + /**
  672 + * Note: This is not supported by the CSS Standard but adds
  673 + * the ability to select items compatible to XPath (i.e.
  674 + * the 3rd element within it's parent).
  675 + *
  676 + * Note: This doesn't conflict with the CSS Standard which
  677 + * doesn't work on numeric attributes anyway.
  678 + */
  679 + if (is_numeric($att_name)
  680 + && $att_expr === ''
  681 + && $att_val === '') {
  682 + $count = 0;
  683 +
  684 + // Find index of current element in parent
  685 + foreach ($node->parent->children as $c) {
  686 + if ($c->tag === $node->tag) ++$count;
  687 + if ($c === $node) break;
  688 + }
  689 +
  690 + // If this is the correct node, continue with next
  691 + // attribute
  692 + if ($count === (int)$att_name) continue;
  693 + }
  694 +
  695 + // Check attribute availability
  696 + if ($att_inv) { // Attribute should NOT be set
  697 + if (isset($node->attr[$att_name])) {
  698 + $pass = false;
  699 + break;
  700 + }
  701 + } else { // Attribute should be set
  702 + // todo: "plaintext" is not a valid CSS selector!
  703 + if ($att_name !== 'plaintext'
  704 + && !isset($node->attr[$att_name])) {
  705 + $pass = false;
  706 + break;
  707 + }
  708 + }
  709 +
  710 + // Continue with next attribute if expression isn't defined
  711 + if ($att_expr === '') continue;
  712 +
  713 + // If they have told us that this is a "plaintext"
  714 + // search then we want the plaintext of the node - right?
  715 + // todo "plaintext" is not a valid CSS selector!
  716 + if ($att_name === 'plaintext') {
  717 + $nodeKeyValue = $node->text();
  718 + } else {
  719 + $nodeKeyValue = $node->attr[$att_name];
  720 + }
  721 +
  722 + if (is_object($debug_object)) {
  723 + $debug_object->debug_log(2,
  724 + 'testing node: '
  725 + . $node->tag
  726 + . ' for attribute: '
  727 + . $att_name
  728 + . $att_expr
  729 + . $att_val
  730 + . ' where nodes value is: '
  731 + . $nodeKeyValue
  732 + );
  733 + }
  734 +
  735 + // If lowercase is set, do a case insensitive test of
  736 + // the value of the selector.
  737 + if ($lowercase) {
  738 + $check = $this->match(
  739 + $att_expr,
  740 + strtolower($att_val),
  741 + strtolower($nodeKeyValue),
  742 + $att_case_sensitivity
  743 + );
  744 + } else {
  745 + $check = $this->match(
  746 + $att_expr,
  747 + $att_val,
  748 + $nodeKeyValue,
  749 + $att_case_sensitivity
  750 + );
  751 + }
  752 +
  753 + if (is_object($debug_object)) {
  754 + $debug_object->debug_log(2,
  755 + 'after match: '
  756 + . ($check ? 'true' : 'false')
  757 + );
  758 + }
  759 +
  760 + if (!$check) {
  761 + $pass = false;
  762 + break;
  763 + }
  764 + }
  765 + }
  766 +
  767 + // Found a match. Add to list and clear node
  768 + if ($pass) $ret[$node->_[HDOM_INFO_BEGIN]] = 1;
  769 + unset($node);
  770 + }
  771 + // It's passed by reference so this is actually what this function returns.
  772 + if (is_object($debug_object)) {
  773 + $debug_object->debug_log(1, 'EXIT - ret: ', $ret);
  774 + }
  775 + }
  776 +
  777 + protected function match($exp, $pattern, $value, $case_sensitivity)
  778 + {
  779 + global $debug_object;
  780 + if (is_object($debug_object)) {$debug_object->debug_log_entry(1);}
  781 +
  782 + if ($case_sensitivity === 'i') {
  783 + $pattern = strtolower($pattern);
  784 + $value = strtolower($value);
  785 + }
  786 +
  787 + switch ($exp) {
  788 + case '=':
  789 + return ($value === $pattern);
  790 + case '!=':
  791 + return ($value !== $pattern);
  792 + case '^=':
  793 + return preg_match('/^' . preg_quote($pattern, '/') . '/', $value);
  794 + case '$=':
  795 + return preg_match('/' . preg_quote($pattern, '/') . '$/', $value);
  796 + case '*=':
  797 + return preg_match('/' . preg_quote($pattern, '/') . '/', $value);
  798 + case '|=':
  799 + /**
  800 + * [att|=val]
  801 + *
  802 + * Represents an element with the att attribute, its value
  803 + * either being exactly "val" or beginning with "val"
  804 + * immediately followed by "-" (U+002D).
  805 + */
  806 + return strpos($value, $pattern) === 0;
  807 + case '~=':
  808 + /**
  809 + * [att~=val]
  810 + *
  811 + * Represents an element with the att attribute whose value is a
  812 + * whitespace-separated list of words, one of which is exactly
  813 + * "val". If "val" contains whitespace, it will never represent
  814 + * anything (since the words are separated by spaces). Also if
  815 + * "val" is the empty string, it will never represent anything.
  816 + */
  817 + return in_array($pattern, explode(' ', trim($value)), true);
  818 + }
  819 + return false;
  820 + }
  821 +
  822 + protected function parse_selector($selector_string)
  823 + {
  824 + global $debug_object;
  825 + if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
  826 +
  827 + /**
  828 + * Pattern of CSS selectors, modified from mootools (https://mootools.net/)
  829 + *
  830 + * Paperg: Add the colon to the attribute, so that it properly finds
  831 + * <tag attr:ibute="something" > like google does.
  832 + *
  833 + * Note: if you try to look at this attribute, you MUST use getAttribute
  834 + * since $dom->x:y will fail the php syntax check.
  835 + *
  836 + * Notice the \[ starting the attribute? and the @? following? This
  837 + * implies that an attribute can begin with an @ sign that is not
  838 + * captured. This implies that an html attribute specifier may start
  839 + * with an @ sign that is NOT captured by the expression. Farther study
  840 + * is required to determine of this should be documented or removed.
  841 + *
  842 + * Matches selectors in this order:
  843 + *
  844 + * [0] - full match
  845 + *
  846 + * [1] - tag name
  847 + * ([\w:\*-]*)
  848 + * Matches the tag name consisting of zero or more words, colons,
  849 + * asterisks and hyphens.
  850 + *
  851 + * [2] - id name
  852 + * (?:\#([\w-]+))
  853 + * Optionally matches a id name, consisting of an "#" followed by
  854 + * the id name (one or more words and hyphens).
  855 + *
  856 + * [3] - class names (including dots)
  857 + * (?:\.([\w\.-]+))?
  858 + * Optionally matches a list of classs, consisting of an "."
  859 + * followed by the class name (one or more words and hyphens)
  860 + * where multiple classes can be chained (i.e. ".foo.bar.baz")
  861 + *
  862 + * [4] - attributes
  863 + * ((?:\[@?(?:!?[\w:-]+)(?:(?:[!*^$|~]?=)[\"']?(?:.*?)[\"']?)?(?:\s*?(?:[iIsS])?)?\])+)?
  864 + * Optionally matches the attributes list
  865 + *
  866 + * [5] - separator
  867 + * ([\/, >+~]+)
  868 + * Matches the selector list separator
  869 + */
  870 + // phpcs:ignore Generic.Files.LineLength
  871 + $pattern = "/([\w:\*-]*)(?:\#([\w-]+))?(?:|\.([\w\.-]+))?((?:\[@?(?:!?[\w:-]+)(?:(?:[!*^$|~]?=)[\"']?(?:.*?)[\"']?)?(?:\s*?(?:[iIsS])?)?\])+)?([\/, >+~]+)/is";
  872 +
  873 + preg_match_all(
  874 + $pattern,
  875 + trim($selector_string) . ' ', // Add final ' ' as pseudo separator
  876 + $matches,
  877 + PREG_SET_ORDER
  878 + );
  879 +
  880 + if (is_object($debug_object)) {
  881 + $debug_object->debug_log(2, 'Matches Array: ', $matches);
  882 + }
  883 +
  884 + $selectors = array();
  885 + $result = array();
  886 +
  887 + foreach ($matches as $m) {
  888 + $m[0] = trim($m[0]);
  889 +
  890 + // Skip NoOps
  891 + if ($m[0] === '' || $m[0] === '/' || $m[0] === '//') { continue; }
  892 +
  893 + // Convert to lowercase
  894 + if ($this->dom->lowercase) {
  895 + $m[1] = strtolower($m[1]);
  896 + }
  897 +
  898 + // Extract classes
  899 + if ($m[3] !== '') { $m[3] = explode('.', $m[3]); }
  900 +
  901 + /* Extract attributes (pattern based on the pattern above!)
  902 +
  903 + * [0] - full match
  904 + * [1] - attribute name
  905 + * [2] - attribute expression
  906 + * [3] - attribute value
  907 + * [4] - case sensitivity
  908 + *
  909 + * Note: Attributes can be negated with a "!" prefix to their name
  910 + */
  911 + if($m[4] !== '') {
  912 + preg_match_all(
  913 + "/\[@?(!?[\w:-]+)(?:([!*^$|~]?=)[\"']?(.*?)[\"']?)?(?:\s+?([iIsS])?)?\]/is",
  914 + trim($m[4]),
  915 + $attributes,
  916 + PREG_SET_ORDER
  917 + );
  918 +
  919 + // Replace element by array
  920 + $m[4] = array();
  921 +
  922 + foreach($attributes as $att) {
  923 + // Skip empty matches
  924 + if(trim($att[0]) === '') { continue; }
  925 +
  926 + $inverted = (isset($att[1][0]) && $att[1][0] === '!');
  927 + $m[4][] = array(
  928 + $inverted ? substr($att[1], 1) : $att[1], // Name
  929 + (isset($att[2])) ? $att[2] : '', // Expression
  930 + (isset($att[3])) ? $att[3] : '', // Value
  931 + $inverted, // Inverted Flag
  932 + (isset($att[4])) ? strtolower($att[4]) : '', // Case-Sensitivity
  933 + );
  934 + }
  935 + }
  936 +
  937 + // Sanitize Separator
  938 + if ($m[5] !== '' && trim($m[5]) === '') { // Descendant Separator
  939 + $m[5] = ' ';
  940 + } else { // Other Separator
  941 + $m[5] = trim($m[5]);
  942 + }
  943 +
  944 + // Clear Separator if it's a Selector List
  945 + if ($is_list = ($m[5] === ',')) { $m[5] = ''; }
  946 +
  947 + // Remove full match before adding to results
  948 + array_shift($m);
  949 + $result[] = $m;
  950 +
  951 + if ($is_list) { // Selector List
  952 + $selectors[] = $result;
  953 + $result = array();
  954 + }
  955 + }
  956 +
  957 + if (count($result) > 0) { $selectors[] = $result; }
  958 + return $selectors;
  959 + }
  960 +
  961 + function __get($name)
  962 + {
  963 + if (isset($this->attr[$name])) {
  964 + return $this->convert_text($this->attr[$name]);
  965 + }
  966 + switch ($name) {
  967 + case 'outertext': return $this->outertext();
  968 + case 'innertext': return $this->innertext();
  969 + case 'plaintext': return $this->text();
  970 + case 'xmltext': return $this->xmltext();
  971 + default: return array_key_exists($name, $this->attr);
  972 + }
  973 + }
  974 +
  975 + function __set($name, $value)
  976 + {
  977 + global $debug_object;
  978 + if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
  979 +
  980 + switch ($name) {
  981 + case 'outertext': return $this->_[HDOM_INFO_OUTER] = $value;
  982 + case 'innertext':
  983 + if (isset($this->_[HDOM_INFO_TEXT])) {
  984 + return $this->_[HDOM_INFO_TEXT] = $value;
  985 + }
  986 + return $this->_[HDOM_INFO_INNER] = $value;
  987 + }
  988 +
  989 + if (!isset($this->attr[$name])) {
  990 + $this->_[HDOM_INFO_SPACE][] = array(' ', '', '');
  991 + $this->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_DOUBLE;
  992 + }
  993 +
  994 + $this->attr[$name] = $value;
  995 + }
  996 +
  997 + function __isset($name)
  998 + {
  999 + switch ($name) {
  1000 + case 'outertext': return true;
  1001 + case 'innertext': return true;
  1002 + case 'plaintext': return true;
  1003 + }
  1004 + //no value attr: nowrap, checked selected...
  1005 + return (array_key_exists($name, $this->attr)) ? true : isset($this->attr[$name]);
  1006 + }
  1007 +
  1008 + function __unset($name)
  1009 + {
  1010 + if (isset($this->attr[$name])) { unset($this->attr[$name]); }
  1011 + }
  1012 +
  1013 + function convert_text($text)
  1014 + {
  1015 + global $debug_object;
  1016 + if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
  1017 +
  1018 + $converted_text = $text;
  1019 +
  1020 + $sourceCharset = '';
  1021 + $targetCharset = '';
  1022 +
  1023 + if ($this->dom) {
  1024 + $sourceCharset = strtoupper($this->dom->_charset);
  1025 + $targetCharset = strtoupper($this->dom->_target_charset);
  1026 + }
  1027 +
  1028 + if (is_object($debug_object)) {
  1029 + $debug_object->debug_log(3,
  1030 + 'source charset: '
  1031 + . $sourceCharset
  1032 + . ' target charaset: '
  1033 + . $targetCharset
  1034 + );
  1035 + }
  1036 +
  1037 + if (!empty($sourceCharset)
  1038 + && !empty($targetCharset)
  1039 + && (strcasecmp($sourceCharset, $targetCharset) != 0)) {
  1040 + // Check if the reported encoding could have been incorrect and the text is actually already UTF-8
  1041 + if ((strcasecmp($targetCharset, 'UTF-8') == 0)
  1042 + && ($this->is_utf8($text))) {
  1043 + $converted_text = $text;
  1044 + } else {
  1045 + $converted_text = iconv($sourceCharset, $targetCharset, $text);
  1046 + }
  1047 + }
  1048 +
  1049 + // Lets make sure that we don't have that silly BOM issue with any of the utf-8 text we output.
  1050 + if ($targetCharset === 'UTF-8') {
  1051 + if (substr($converted_text, 0, 3) === "\xef\xbb\xbf") {
  1052 + $converted_text = substr($converted_text, 3);
  1053 + }
  1054 +
  1055 + if (substr($converted_text, -3) === "\xef\xbb\xbf") {
  1056 + $converted_text = substr($converted_text, 0, -3);
  1057 + }
  1058 + }
  1059 +
  1060 + return $converted_text;
  1061 + }
  1062 +
  1063 + static function is_utf8($str)
  1064 + {
  1065 + $c = 0; $b = 0;
  1066 + $bits = 0;
  1067 + $len = strlen($str);
  1068 + for($i = 0; $i < $len; $i++) {
  1069 + $c = ord($str[$i]);
  1070 + if($c > 128) {
  1071 + if(($c >= 254)) { return false; }
  1072 + elseif($c >= 252) { $bits = 6; }
  1073 + elseif($c >= 248) { $bits = 5; }
  1074 + elseif($c >= 240) { $bits = 4; }
  1075 + elseif($c >= 224) { $bits = 3; }
  1076 + elseif($c >= 192) { $bits = 2; }
  1077 + else { return false; }
  1078 + if(($i + $bits) > $len) { return false; }
  1079 + while($bits > 1) {
  1080 + $i++;
  1081 + $b = ord($str[$i]);
  1082 + if($b < 128 || $b > 191) { return false; }
  1083 + $bits--;
  1084 + }
  1085 + }
  1086 + }
  1087 + return true;
  1088 + }
  1089 +
  1090 + function get_display_size()
  1091 + {
  1092 + global $debug_object;
  1093 +
  1094 + $width = -1;
  1095 + $height = -1;
  1096 +
  1097 + if ($this->tag !== 'img') {
  1098 + return false;
  1099 + }
  1100 +
  1101 + // See if there is aheight or width attribute in the tag itself.
  1102 + if (isset($this->attr['width'])) {
  1103 + $width = $this->attr['width'];
  1104 + }
  1105 +
  1106 + if (isset($this->attr['height'])) {
  1107 + $height = $this->attr['height'];
  1108 + }
  1109 +
  1110 + // Now look for an inline style.
  1111 + if (isset($this->attr['style'])) {
  1112 + // Thanks to user gnarf from stackoverflow for this regular expression.
  1113 + $attributes = array();
  1114 +
  1115 + preg_match_all(
  1116 + '/([\w-]+)\s*:\s*([^;]+)\s*;?/',
  1117 + $this->attr['style'],
  1118 + $matches,
  1119 + PREG_SET_ORDER
  1120 + );
  1121 +
  1122 + foreach ($matches as $match) {
  1123 + $attributes[$match[1]] = $match[2];
  1124 + }
  1125 +
  1126 + // If there is a width in the style attributes:
  1127 + if (isset($attributes['width']) && $width == -1) {
  1128 + // check that the last two characters are px (pixels)
  1129 + if (strtolower(substr($attributes['width'], -2)) === 'px') {
  1130 + $proposed_width = substr($attributes['width'], 0, -2);
  1131 + // Now make sure that it's an integer and not something stupid.
  1132 + if (filter_var($proposed_width, FILTER_VALIDATE_INT)) {
  1133 + $width = $proposed_width;
  1134 + }
  1135 + }
  1136 + }
  1137 +
  1138 + // If there is a width in the style attributes:
  1139 + if (isset($attributes['height']) && $height == -1) {
  1140 + // check that the last two characters are px (pixels)
  1141 + if (strtolower(substr($attributes['height'], -2)) == 'px') {
  1142 + $proposed_height = substr($attributes['height'], 0, -2);
  1143 + // Now make sure that it's an integer and not something stupid.
  1144 + if (filter_var($proposed_height, FILTER_VALIDATE_INT)) {
  1145 + $height = $proposed_height;
  1146 + }
  1147 + }
  1148 + }
  1149 +
  1150 + }
  1151 +
  1152 + // Future enhancement:
  1153 + // Look in the tag to see if there is a class or id specified that has
  1154 + // a height or width attribute to it.
  1155 +
  1156 + // Far future enhancement
  1157 + // Look at all the parent tags of this image to see if they specify a
  1158 + // class or id that has an img selector that specifies a height or width
  1159 + // Note that in this case, the class or id will have the img subselector
  1160 + // for it to apply to the image.
  1161 +
  1162 + // ridiculously far future development
  1163 + // If the class or id is specified in a SEPARATE css file thats not on
  1164 + // the page, go get it and do what we were just doing for the ones on
  1165 + // the page.
  1166 +
  1167 + $result = array(
  1168 + 'height' => $height,
  1169 + 'width' => $width
  1170 + );
  1171 +
  1172 + return $result;
  1173 + }
  1174 +
  1175 + function save($filepath = '')
  1176 + {
  1177 + $ret = $this->outertext();
  1178 +
  1179 + if ($filepath !== '') {
  1180 + file_put_contents($filepath, $ret, LOCK_EX);
  1181 + }
  1182 +
  1183 + return $ret;
  1184 + }
  1185 +
  1186 + function addClass($class)
  1187 + {
  1188 + if (is_string($class)) {
  1189 + $class = explode(' ', $class);
  1190 + }
  1191 +
  1192 + if (is_array($class)) {
  1193 + foreach($class as $c) {
  1194 + if (isset($this->class)) {
  1195 + if ($this->hasClass($c)) {
  1196 + continue;
  1197 + } else {
  1198 + $this->class .= ' ' . $c;
  1199 + }
  1200 + } else {
  1201 + $this->class = $c;
  1202 + }
  1203 + }
  1204 + } else {
  1205 + if (is_object($debug_object)) {
  1206 + $debug_object->debug_log(2, 'Invalid type: ', gettype($class));
  1207 + }
  1208 + }
  1209 + }
  1210 +
  1211 + function hasClass($class)
  1212 + {
  1213 + if (is_string($class)) {
  1214 + if (isset($this->class)) {
  1215 + return in_array($class, explode(' ', $this->class), true);
  1216 + }
  1217 + } else {
  1218 + if (is_object($debug_object)) {
  1219 + $debug_object->debug_log(2, 'Invalid type: ', gettype($class));
  1220 + }
  1221 + }
  1222 +
  1223 + return false;
  1224 + }
  1225 +
  1226 + function removeClass($class = null)
  1227 + {
  1228 + if (!isset($this->class)) {
  1229 + return;
  1230 + }
  1231 +
  1232 + if (is_null($class)) {
  1233 + $this->removeAttribute('class');
  1234 + return;
  1235 + }
  1236 +
  1237 + if (is_string($class)) {
  1238 + $class = explode(' ', $class);
  1239 + }
  1240 +
  1241 + if (is_array($class)) {
  1242 + $class = array_diff(explode(' ', $this->class), $class);
  1243 + if (empty($class)) {
  1244 + $this->removeAttribute('class');
  1245 + } else {
  1246 + $this->class = implode(' ', $class);
  1247 + }
  1248 + }
  1249 + }
  1250 +
  1251 + function getAllAttributes()
  1252 + {
  1253 + return $this->attr;
  1254 + }
  1255 +
  1256 + function getAttribute($name)
  1257 + {
  1258 + return $this->__get($name);
  1259 + }
  1260 +
  1261 + function setAttribute($name, $value)
  1262 + {
  1263 + $this->__set($name, $value);
  1264 + }
  1265 +
  1266 + function hasAttribute($name)
  1267 + {
  1268 + return $this->__isset($name);
  1269 + }
  1270 +
  1271 + function removeAttribute($name)
  1272 + {
  1273 + $this->__set($name, null);
  1274 + }
  1275 +
  1276 + function remove()
  1277 + {
  1278 + if ($this->parent) {
  1279 + $this->parent->removeChild($this);
  1280 + }
  1281 + }
  1282 +
  1283 + function removeChild($node)
  1284 + {
  1285 + $nidx = array_search($node, $this->nodes, true);
  1286 + $cidx = array_search($node, $this->children, true);
  1287 + $didx = array_search($node, $this->dom->nodes, true);
  1288 +
  1289 + if ($nidx !== false && $cidx !== false && $didx !== false) {
  1290 +
  1291 + foreach($node->children as $child) {
  1292 + $node->removeChild($child);
  1293 + }
  1294 +
  1295 + foreach($node->nodes as $entity) {
  1296 + $enidx = array_search($entity, $node->nodes, true);
  1297 + $edidx = array_search($entity, $node->dom->nodes, true);
  1298 +
  1299 + if ($enidx !== false && $edidx !== false) {
  1300 + unset($node->nodes[$enidx]);
  1301 + unset($node->dom->nodes[$edidx]);
  1302 + }
  1303 + }
  1304 +
  1305 + unset($this->nodes[$nidx]);
  1306 + unset($this->children[$cidx]);
  1307 + unset($this->dom->nodes[$didx]);
  1308 +
  1309 + $node->clear();
  1310 +
  1311 + }
  1312 + }
  1313 +
  1314 + function getElementById($id)
  1315 + {
  1316 + return $this->find("#$id", 0);
  1317 + }
  1318 +
  1319 + function getElementsById($id, $idx = null)
  1320 + {
  1321 + return $this->find("#$id", $idx);
  1322 + }
  1323 +
  1324 + function getElementByTagName($name)
  1325 + {
  1326 + return $this->find($name, 0);
  1327 + }
  1328 +
  1329 + function getElementsByTagName($name, $idx = null)
  1330 + {
  1331 + return $this->find($name, $idx);
  1332 + }
  1333 +
  1334 + function parentNode()
  1335 + {
  1336 + return $this->parent();
  1337 + }
  1338 +
  1339 + function childNodes($idx = -1)
  1340 + {
  1341 + return $this->children($idx);
  1342 + }
  1343 +
  1344 + function firstChild()
  1345 + {
  1346 + return $this->first_child();
  1347 + }
  1348 +
  1349 + function lastChild()
  1350 + {
  1351 + return $this->last_child();
  1352 + }
  1353 +
  1354 + function nextSibling()
  1355 + {
  1356 + return $this->next_sibling();
  1357 + }
  1358 +
  1359 + function previousSibling()
  1360 + {
  1361 + return $this->prev_sibling();
  1362 + }
  1363 +
  1364 + function hasChildNodes()
  1365 + {
  1366 + return $this->has_child();
  1367 + }
  1368 +
  1369 + function nodeName()
  1370 + {
  1371 + return $this->tag;
  1372 + }
  1373 +
  1374 + function appendChild($node)
  1375 + {
  1376 + $node->parent($this);
  1377 + return $node;
  1378 + }
  1379 +
  1380 +}
  1381 +
  1382 +class simple_html_dom
  1383 +{
  1384 + public $root = null;
  1385 + public $nodes = array();
  1386 + public $callback = null;
  1387 + public $lowercase = false;
  1388 + public $original_size;
  1389 + public $size;
  1390 +
  1391 + protected $pos;
  1392 + protected $doc;
  1393 + protected $char;
  1394 +
  1395 + protected $cursor;
  1396 + protected $parent;
  1397 + protected $noise = array();
  1398 + protected $token_blank = " \t\r\n";
  1399 + protected $token_equal = ' =/>';
  1400 + protected $token_slash = " />\r\n\t";
  1401 + protected $token_attr = ' >';
  1402 +
  1403 + public $_charset = '';
  1404 + public $_target_charset = '';
  1405 +
  1406 + protected $default_br_text = '';
  1407 +
  1408 + public $default_span_text = '';
  1409 +
  1410 + protected $self_closing_tags = array(
  1411 + 'area' => 1,
  1412 + 'base' => 1,
  1413 + 'br' => 1,
  1414 + 'col' => 1,
  1415 + 'embed' => 1,
  1416 + 'hr' => 1,
  1417 + 'img' => 1,
  1418 + 'input' => 1,
  1419 + 'link' => 1,
  1420 + 'meta' => 1,
  1421 + 'param' => 1,
  1422 + 'source' => 1,
  1423 + 'track' => 1,
  1424 + 'wbr' => 1
  1425 + );
  1426 + protected $block_tags = array(
  1427 + 'body' => 1,
  1428 + 'div' => 1,
  1429 + 'form' => 1,
  1430 + 'root' => 1,
  1431 + 'span' => 1,
  1432 + 'table' => 1
  1433 + );
  1434 + protected $optional_closing_tags = array(
  1435 + // Not optional, see
  1436 + // https://www.w3.org/TR/html/textlevel-semantics.html#the-b-element
  1437 + 'b' => array('b' => 1),
  1438 + 'dd' => array('dd' => 1, 'dt' => 1),
  1439 + // Not optional, see
  1440 + // https://www.w3.org/TR/html/grouping-content.html#the-dl-element
  1441 + 'dl' => array('dd' => 1, 'dt' => 1),
  1442 + 'dt' => array('dd' => 1, 'dt' => 1),
  1443 + 'li' => array('li' => 1),
  1444 + 'optgroup' => array('optgroup' => 1, 'option' => 1),
  1445 + 'option' => array('optgroup' => 1, 'option' => 1),
  1446 + 'p' => array('p' => 1),
  1447 + 'rp' => array('rp' => 1, 'rt' => 1),
  1448 + 'rt' => array('rp' => 1, 'rt' => 1),
  1449 + 'td' => array('td' => 1, 'th' => 1),
  1450 + 'th' => array('td' => 1, 'th' => 1),
  1451 + 'tr' => array('td' => 1, 'th' => 1, 'tr' => 1),
  1452 + );
  1453 +
  1454 + function __construct(
  1455 + $str = null,
  1456 + $lowercase = true,
  1457 + $forceTagsClosed = true,
  1458 + $target_charset = DEFAULT_TARGET_CHARSET,
  1459 + $stripRN = true,
  1460 + $defaultBRText = DEFAULT_BR_TEXT,
  1461 + $defaultSpanText = DEFAULT_SPAN_TEXT,
  1462 + $options = 0)
  1463 + {
  1464 + if ($str) {
  1465 + if (preg_match('/^http:\/\//i', $str) || is_file($str)) {
  1466 + $this->load_file($str);
  1467 + } else {
  1468 + $this->load(
  1469 + $str,
  1470 + $lowercase,
  1471 + $stripRN,
  1472 + $defaultBRText,
  1473 + $defaultSpanText,
  1474 + $options
  1475 + );
  1476 + }
  1477 + }
  1478 + // Forcing tags to be closed implies that we don't trust the html, but
  1479 + // it can lead to parsing errors if we SHOULD trust the html.
  1480 + if (!$forceTagsClosed) {
  1481 + $this->optional_closing_array = array();
  1482 + }
  1483 +
  1484 + $this->_target_charset = $target_charset;
  1485 + }
  1486 +
  1487 + function __destruct()
  1488 + {
  1489 + $this->clear();
  1490 + }
  1491 +
  1492 + function load(
  1493 + $str,
  1494 + $lowercase = true,
  1495 + $stripRN = true,
  1496 + $defaultBRText = DEFAULT_BR_TEXT,
  1497 + $defaultSpanText = DEFAULT_SPAN_TEXT,
  1498 + $options = 0)
  1499 + {
  1500 + global $debug_object;
  1501 +
  1502 + // prepare
  1503 + $this->prepare($str, $lowercase, $defaultBRText, $defaultSpanText);
  1504 +
  1505 + // Per sourceforge http://sourceforge.net/tracker/?func=detail&aid=2949097&group_id=218559&atid=1044037
  1506 + // Script tags removal now preceeds style tag removal.
  1507 + // strip out <script> tags
  1508 + $this->remove_noise("'<\s*script[^>]*[^/]>(.*?)<\s*/\s*script\s*>'is");
  1509 + $this->remove_noise("'<\s*script\s*>(.*?)<\s*/\s*script\s*>'is");
  1510 +
  1511 + // strip out the \r \n's if we are told to.
  1512 + if ($stripRN) {
  1513 + $this->doc = str_replace("\r", ' ', $this->doc);
  1514 + $this->doc = str_replace("\n", ' ', $this->doc);
  1515 +
  1516 + // set the length of content since we have changed it.
  1517 + $this->size = strlen($this->doc);
  1518 + }
  1519 +
  1520 + // strip out cdata
  1521 + $this->remove_noise("'<!\[CDATA\[(.*?)\]\]>'is", true);
  1522 + // strip out comments
  1523 + $this->remove_noise("'<!--(.*?)-->'is");
  1524 + // strip out <style> tags
  1525 + $this->remove_noise("'<\s*style[^>]*[^/]>(.*?)<\s*/\s*style\s*>'is");
  1526 + $this->remove_noise("'<\s*style\s*>(.*?)<\s*/\s*style\s*>'is");
  1527 + // strip out preformatted tags
  1528 + $this->remove_noise("'<\s*(?:code)[^>]*>(.*?)<\s*/\s*(?:code)\s*>'is");
  1529 + // strip out server side scripts
  1530 + $this->remove_noise("'(<\?)(.*?)(\?>)'s", true);
  1531 +
  1532 + if($options & HDOM_SMARTY_AS_TEXT) { // Strip Smarty scripts
  1533 + $this->remove_noise("'(\{\w)(.*?)(\})'s", true);
  1534 + }
  1535 +
  1536 + // parsing
  1537 + $this->parse();
  1538 + // end
  1539 + $this->root->_[HDOM_INFO_END] = $this->cursor;
  1540 + $this->parse_charset();
  1541 +
  1542 + // make load function chainable
  1543 + return $this;
  1544 + }
  1545 +
  1546 + function load_file()
  1547 + {
  1548 + $args = func_get_args();
  1549 +
  1550 + if(($doc = call_user_func_array('file_get_contents', $args)) !== false) {
  1551 + $this->load($doc, true);
  1552 + } else {
  1553 + return false;
  1554 + }
  1555 + }
  1556 +
  1557 + function set_callback($function_name)
  1558 + {
  1559 + $this->callback = $function_name;
  1560 + }
  1561 +
  1562 + function remove_callback()
  1563 + {
  1564 + $this->callback = null;
  1565 + }
  1566 +
  1567 + function save($filepath = '')
  1568 + {
  1569 + $ret = $this->root->innertext();
  1570 + if ($filepath !== '') { file_put_contents($filepath, $ret, LOCK_EX); }
  1571 + return $ret;
  1572 + }
  1573 +
  1574 + function find($selector, $idx = null, $lowercase = false)
  1575 + {
  1576 + return $this->root->find($selector, $idx, $lowercase);
  1577 + }
  1578 +
  1579 + function clear()
  1580 + {
  1581 + if (isset($this->nodes)) {
  1582 + foreach ($this->nodes as $n) {
  1583 + $n->clear();
  1584 + $n = null;
  1585 + }
  1586 + }
  1587 +
  1588 + // This add next line is documented in the sourceforge repository.
  1589 + // 2977248 as a fix for ongoing memory leaks that occur even with the
  1590 + // use of clear.
  1591 + if (isset($this->children)) {
  1592 + foreach ($this->children as $n) {
  1593 + $n->clear();
  1594 + $n = null;
  1595 + }
  1596 + }
  1597 +
  1598 + if (isset($this->parent)) {
  1599 + $this->parent->clear();
  1600 + unset($this->parent);
  1601 + }
  1602 +
  1603 + if (isset($this->root)) {
  1604 + $this->root->clear();
  1605 + unset($this->root);
  1606 + }
  1607 +
  1608 + unset($this->doc);
  1609 + unset($this->noise);
  1610 + }
  1611 +
  1612 + function dump($show_attr = true)
  1613 + {
  1614 + $this->root->dump($show_attr);
  1615 + }
  1616 +
  1617 + protected function prepare(
  1618 + $str, $lowercase = true,
  1619 + $defaultBRText = DEFAULT_BR_TEXT,
  1620 + $defaultSpanText = DEFAULT_SPAN_TEXT)
  1621 + {
  1622 + $this->clear();
  1623 +
  1624 + $this->doc = trim($str);
  1625 + $this->size = strlen($this->doc);
  1626 + $this->original_size = $this->size; // original size of the html
  1627 + $this->pos = 0;
  1628 + $this->cursor = 1;
  1629 + $this->noise = array();
  1630 + $this->nodes = array();
  1631 + $this->lowercase = $lowercase;
  1632 + $this->default_br_text = $defaultBRText;
  1633 + $this->default_span_text = $defaultSpanText;
  1634 + $this->root = new simple_html_dom_node($this);
  1635 + $this->root->tag = 'root';
  1636 + $this->root->_[HDOM_INFO_BEGIN] = -1;
  1637 + $this->root->nodetype = HDOM_TYPE_ROOT;
  1638 + $this->parent = $this->root;
  1639 + if ($this->size > 0) { $this->char = $this->doc[0]; }
  1640 + }
  1641 +
  1642 + protected function parse()
  1643 + {
  1644 + while (true) {
  1645 + // Read next tag if there is no text between current position and the
  1646 + // next opening tag.
  1647 + if (($s = $this->copy_until_char('<')) === '') {
  1648 + if($this->read_tag()) {
  1649 + continue;
  1650 + } else {
  1651 + return true;
  1652 + }
  1653 + }
  1654 +
  1655 + // Add a text node for text between tags
  1656 + $node = new simple_html_dom_node($this);
  1657 + ++$this->cursor;
  1658 + $node->_[HDOM_INFO_TEXT] = $s;
  1659 + $this->link_nodes($node, false);
  1660 + }
  1661 + }
  1662 +
  1663 + protected function parse_charset()
  1664 + {
  1665 + global $debug_object;
  1666 +
  1667 + $charset = null;
  1668 +
  1669 + if (function_exists('get_last_retrieve_url_contents_content_type')) {
  1670 + $contentTypeHeader = get_last_retrieve_url_contents_content_type();
  1671 + $success = preg_match('/charset=(.+)/', $contentTypeHeader, $matches);
  1672 + if ($success) {
  1673 + $charset = $matches[1];
  1674 + if (is_object($debug_object)) {
  1675 + $debug_object->debug_log(2,
  1676 + 'header content-type found charset of: '
  1677 + . $charset
  1678 + );
  1679 + }
  1680 + }
  1681 + }
  1682 +
  1683 + if (empty($charset)) {
  1684 + // https://www.w3.org/TR/html/document-metadata.html#statedef-http-equiv-content-type
  1685 + $el = $this->root->find('meta[http-equiv=Content-Type]', 0, true);
  1686 +
  1687 + if (!empty($el)) {
  1688 + $fullvalue = $el->content;
  1689 + if (is_object($debug_object)) {
  1690 + $debug_object->debug_log(2,
  1691 + 'meta content-type tag found'
  1692 + . $fullvalue
  1693 + );
  1694 + }
  1695 +
  1696 + if (!empty($fullvalue)) {
  1697 + $success = preg_match(
  1698 + '/charset=(.+)/i',
  1699 + $fullvalue,
  1700 + $matches
  1701 + );
  1702 +
  1703 + if ($success) {
  1704 + $charset = $matches[1];
  1705 + } else {
  1706 + // If there is a meta tag, and they don't specify the
  1707 + // character set, research says that it's typically
  1708 + // ISO-8859-1
  1709 + if (is_object($debug_object)) {
  1710 + $debug_object->debug_log(2,
  1711 + 'meta content-type tag couldn\'t be parsed. using iso-8859 default.'
  1712 + );
  1713 + }
  1714 +
  1715 + $charset = 'ISO-8859-1';
  1716 + }
  1717 + }
  1718 + }
  1719 + }
  1720 +
  1721 + if (empty($charset)) {
  1722 + // https://www.w3.org/TR/html/document-metadata.html#character-encoding-declaration
  1723 + if ($meta = $this->root->find('meta[charset]', 0)) {
  1724 + $charset = $meta->charset;
  1725 + if (is_object($debug_object)) {
  1726 + $debug_object->debug_log(2, 'meta charset: ' . $charset);
  1727 + }
  1728 + }
  1729 + }
  1730 +
  1731 + if (empty($charset)) {
  1732 + // Try to guess the charset based on the content
  1733 + // Requires Multibyte String (mbstring) support (optional)
  1734 + if (function_exists('mb_detect_encoding')) {
  1735 + /**
  1736 + * mb_detect_encoding() is not intended to distinguish between
  1737 + * charsets, especially single-byte charsets. Its primary
  1738 + * purpose is to detect which multibyte encoding is in use,
  1739 + * i.e. UTF-8, UTF-16, shift-JIS, etc.
  1740 + *
  1741 + * -- https://bugs.php.net/bug.php?id=38138
  1742 + *
  1743 + * Adding both CP1251/ISO-8859-5 and CP1252/ISO-8859-1 will
  1744 + * always result in CP1251/ISO-8859-5 and vice versa.
  1745 + *
  1746 + * Thus, only detect if it's either UTF-8 or CP1252/ISO-8859-1
  1747 + * to stay compatible.
  1748 + */
  1749 + $encoding = mb_detect_encoding(
  1750 + $this->doc,
  1751 + array( 'UTF-8', 'CP1252', 'ISO-8859-1' )
  1752 + );
  1753 +
  1754 + if ($encoding === 'CP1252' || $encoding === 'ISO-8859-1') {
  1755 + // Due to a limitation of mb_detect_encoding
  1756 + // 'CP1251'/'ISO-8859-5' will be detected as
  1757 + // 'CP1252'/'ISO-8859-1'. This will cause iconv to fail, in
  1758 + // which case we can simply assume it is the other charset.
  1759 + if (!@iconv('CP1252', 'UTF-8', $this->doc)) {
  1760 + $encoding = 'CP1251';
  1761 + }
  1762 + }
  1763 +
  1764 + if ($encoding !== false) {
  1765 + $charset = $encoding;
  1766 + if (is_object($debug_object)) {
  1767 + $debug_object->debug_log(2, 'mb_detect: ' . $charset);
  1768 + }
  1769 + }
  1770 + }
  1771 + }
  1772 +
  1773 + if (empty($charset)) {
  1774 + // Assume it's UTF-8 as it is the most likely charset to be used
  1775 + $charset = 'UTF-8';
  1776 + if (is_object($debug_object)) {
  1777 + $debug_object->debug_log(2, 'No match found, assume ' . $charset);
  1778 + }
  1779 + }
  1780 +
  1781 + // Since CP1252 is a superset, if we get one of it's subsets, we want
  1782 + // it instead.
  1783 + if ((strtolower($charset) == 'iso-8859-1')
  1784 + || (strtolower($charset) == 'latin1')
  1785 + || (strtolower($charset) == 'latin-1')) {
  1786 + $charset = 'CP1252';
  1787 + if (is_object($debug_object)) {
  1788 + $debug_object->debug_log(2,
  1789 + 'replacing ' . $charset . ' with CP1252 as its a superset'
  1790 + );
  1791 + }
  1792 + }
  1793 +
  1794 + if (is_object($debug_object)) {
  1795 + $debug_object->debug_log(1, 'EXIT - ' . $charset);
  1796 + }
  1797 +
  1798 + return $this->_charset = $charset;
  1799 + }
  1800 +
  1801 + protected function read_tag()
  1802 + {
  1803 + // Set end position if no further tags found
  1804 + if ($this->char !== '<') {
  1805 + $this->root->_[HDOM_INFO_END] = $this->cursor;
  1806 + return false;
  1807 + }
  1808 +
  1809 + $begin_tag_pos = $this->pos;
  1810 + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
  1811 +
  1812 + // end tag
  1813 + if ($this->char === '/') {
  1814 + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
  1815 +
  1816 + // Skip whitespace in end tags (i.e. in "</ html>")
  1817 + $this->skip($this->token_blank);
  1818 + $tag = $this->copy_until_char('>');
  1819 +
  1820 + // Skip attributes in end tags
  1821 + if (($pos = strpos($tag, ' ')) !== false) {
  1822 + $tag = substr($tag, 0, $pos);
  1823 + }
  1824 +
  1825 + $parent_lower = strtolower($this->parent->tag);
  1826 + $tag_lower = strtolower($tag);
  1827 +
  1828 + // The end tag is supposed to close the parent tag. Handle situations
  1829 + // when it doesn't
  1830 + if ($parent_lower !== $tag_lower) {
  1831 + // Parent tag does not have to be closed necessarily (optional closing tag)
  1832 + // Current tag is a block tag, so it may close an ancestor
  1833 + if (isset($this->optional_closing_tags[$parent_lower])
  1834 + && isset($this->block_tags[$tag_lower])) {
  1835 +
  1836 + $this->parent->_[HDOM_INFO_END] = 0;
  1837 + $org_parent = $this->parent;
  1838 +
  1839 + // Traverse ancestors to find a matching opening tag
  1840 + // Stop at root node
  1841 + while (($this->parent->parent)
  1842 + && strtolower($this->parent->tag) !== $tag_lower
  1843 + ){
  1844 + $this->parent = $this->parent->parent;
  1845 + }
  1846 +
  1847 + // If we don't have a match add current tag as text node
  1848 + if (strtolower($this->parent->tag) !== $tag_lower) {
  1849 + $this->parent = $org_parent; // restore origonal parent
  1850 +
  1851 + if ($this->parent->parent) {
  1852 + $this->parent = $this->parent->parent;
  1853 + }
  1854 +
  1855 + $this->parent->_[HDOM_INFO_END] = $this->cursor;
  1856 + return $this->as_text_node($tag);
  1857 + }
  1858 + } elseif (($this->parent->parent)
  1859 + && isset($this->block_tags[$tag_lower])
  1860 + ) {
  1861 + // Grandparent exists and current tag is a block tag, so our
  1862 + // parent doesn't have an end tag
  1863 + $this->parent->_[HDOM_INFO_END] = 0; // No end tag
  1864 + $org_parent = $this->parent;
  1865 +
  1866 + // Traverse ancestors to find a matching opening tag
  1867 + // Stop at root node
  1868 + while (($this->parent->parent)
  1869 + && strtolower($this->parent->tag) !== $tag_lower
  1870 + ) {
  1871 + $this->parent = $this->parent->parent;
  1872 + }
  1873 +
  1874 + // If we don't have a match add current tag as text node
  1875 + if (strtolower($this->parent->tag) !== $tag_lower) {
  1876 + $this->parent = $org_parent; // restore origonal parent
  1877 + $this->parent->_[HDOM_INFO_END] = $this->cursor;
  1878 + return $this->as_text_node($tag);
  1879 + }
  1880 + } elseif (($this->parent->parent)
  1881 + && strtolower($this->parent->parent->tag) === $tag_lower
  1882 + ) { // Grandparent exists and current tag closes it
  1883 + $this->parent->_[HDOM_INFO_END] = 0;
  1884 + $this->parent = $this->parent->parent;
  1885 + } else { // Random tag, add as text node
  1886 + return $this->as_text_node($tag);
  1887 + }
  1888 + }
  1889 +
  1890 + // Set end position of parent tag to current cursor position
  1891 + $this->parent->_[HDOM_INFO_END] = $this->cursor;
  1892 +
  1893 + if ($this->parent->parent) {
  1894 + $this->parent = $this->parent->parent;
  1895 + }
  1896 +
  1897 + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
  1898 + return true;
  1899 + }
  1900 +
  1901 + // start tag
  1902 + $node = new simple_html_dom_node($this);
  1903 + $node->_[HDOM_INFO_BEGIN] = $this->cursor;
  1904 + ++$this->cursor;
  1905 + $tag = $this->copy_until($this->token_slash); // Get tag name
  1906 + $node->tag_start = $begin_tag_pos;
  1907 +
  1908 + // doctype, cdata & comments...
  1909 + // <!DOCTYPE html>
  1910 + // <![CDATA[ ... ]]>
  1911 + // <!-- Comment -->
  1912 + if (isset($tag[0]) && $tag[0] === '!') {
  1913 + $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until_char('>');
  1914 +
  1915 + if (isset($tag[2]) && $tag[1] === '-' && $tag[2] === '-') { // Comment ("<!--")
  1916 + $node->nodetype = HDOM_TYPE_COMMENT;
  1917 + $node->tag = 'comment';
  1918 + } else { // Could be doctype or CDATA but we don't care
  1919 + $node->nodetype = HDOM_TYPE_UNKNOWN;
  1920 + $node->tag = 'unknown';
  1921 + }
  1922 +
  1923 + if ($this->char === '>') { $node->_[HDOM_INFO_TEXT] .= '>'; }
  1924 +
  1925 + $this->link_nodes($node, true);
  1926 + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
  1927 + return true;
  1928 + }
  1929 +
  1930 + // The start tag cannot contain another start tag, if so add as text
  1931 + // i.e. "<<html>"
  1932 + if ($pos = strpos($tag, '<') !== false) {
  1933 + $tag = '<' . substr($tag, 0, -1);
  1934 + $node->_[HDOM_INFO_TEXT] = $tag;
  1935 + $this->link_nodes($node, false);
  1936 + $this->char = $this->doc[--$this->pos]; // prev
  1937 + return true;
  1938 + }
  1939 +
  1940 + // Handle invalid tag names (i.e. "<html#doc>")
  1941 + if (!preg_match('/^\w[\w:-]*$/', $tag)) {
  1942 + $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until('<>');
  1943 +
  1944 + // Next char is the beginning of a new tag, don't touch it.
  1945 + if ($this->char === '<') {
  1946 + $this->link_nodes($node, false);
  1947 + return true;
  1948 + }
  1949 +
  1950 + // Next char closes current tag, add and be done with it.
  1951 + if ($this->char === '>') { $node->_[HDOM_INFO_TEXT] .= '>'; }
  1952 + $this->link_nodes($node, false);
  1953 + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
  1954 + return true;
  1955 + }
  1956 +
  1957 + // begin tag, add new node
  1958 + $node->nodetype = HDOM_TYPE_ELEMENT;
  1959 + $tag_lower = strtolower($tag);
  1960 + $node->tag = ($this->lowercase) ? $tag_lower : $tag;
  1961 +
  1962 + // handle optional closing tags
  1963 + if (isset($this->optional_closing_tags[$tag_lower])) {
  1964 + // Traverse ancestors to close all optional closing tags
  1965 + while (isset($this->optional_closing_tags[$tag_lower][strtolower($this->parent->tag)])) {
  1966 + $this->parent->_[HDOM_INFO_END] = 0;
  1967 + $this->parent = $this->parent->parent;
  1968 + }
  1969 + $node->parent = $this->parent;
  1970 + }
  1971 +
  1972 + $guard = 0; // prevent infinity loop
  1973 +
  1974 + // [0] Space between tag and first attribute
  1975 + $space = array($this->copy_skip($this->token_blank), '', '');
  1976 +
  1977 + // attributes
  1978 + do {
  1979 + // Everything until the first equal sign should be the attribute name
  1980 + $name = $this->copy_until($this->token_equal);
  1981 +
  1982 + if ($name === '' && $this->char !== null && $space[0] === '') {
  1983 + break;
  1984 + }
  1985 +
  1986 + if ($guard === $this->pos) { // Escape infinite loop
  1987 + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
  1988 + continue;
  1989 + }
  1990 +
  1991 + $guard = $this->pos;
  1992 +
  1993 + // handle endless '<'
  1994 + // Out of bounds before the tag ended
  1995 + if ($this->pos >= $this->size - 1 && $this->char !== '>') {
  1996 + $node->nodetype = HDOM_TYPE_TEXT;
  1997 + $node->_[HDOM_INFO_END] = 0;
  1998 + $node->_[HDOM_INFO_TEXT] = '<' . $tag . $space[0] . $name;
  1999 + $node->tag = 'text';
  2000 + $this->link_nodes($node, false);
  2001 + return true;
  2002 + }
  2003 +
  2004 + // handle mismatch '<'
  2005 + // Attributes cannot start after opening tag
  2006 + if ($this->doc[$this->pos - 1] == '<') {
  2007 + $node->nodetype = HDOM_TYPE_TEXT;
  2008 + $node->tag = 'text';
  2009 + $node->attr = array();
  2010 + $node->_[HDOM_INFO_END] = 0;
  2011 + $node->_[HDOM_INFO_TEXT] = substr(
  2012 + $this->doc,
  2013 + $begin_tag_pos,
  2014 + $this->pos - $begin_tag_pos - 1
  2015 + );
  2016 + $this->pos -= 2;
  2017 + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
  2018 + $this->link_nodes($node, false);
  2019 + return true;
  2020 + }
  2021 +
  2022 + if ($name !== '/' && $name !== '') { // this is a attribute name
  2023 + // [1] Whitespace after attribute name
  2024 + $space[1] = $this->copy_skip($this->token_blank);
  2025 +
  2026 + $name = $this->restore_noise($name); // might be a noisy name
  2027 +
  2028 + if ($this->lowercase) { $name = strtolower($name); }
  2029 +
  2030 + if ($this->char === '=') { // attribute with value
  2031 + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
  2032 + $this->parse_attr($node, $name, $space); // get attribute value
  2033 + } else {
  2034 + //no value attr: nowrap, checked selected...
  2035 + $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_NO;
  2036 + $node->attr[$name] = true;
  2037 + if ($this->char != '>') { $this->char = $this->doc[--$this->pos]; } // prev
  2038 + }
  2039 +
  2040 + $node->_[HDOM_INFO_SPACE][] = $space;
  2041 +
  2042 + // prepare for next attribute
  2043 + $space = array(
  2044 + $this->copy_skip($this->token_blank),
  2045 + '',
  2046 + ''
  2047 + );
  2048 + } else { // no more attributes
  2049 + break;
  2050 + }
  2051 + } while ($this->char !== '>' && $this->char !== '/'); // go until the tag ended
  2052 +
  2053 + $this->link_nodes($node, true);
  2054 + $node->_[HDOM_INFO_ENDSPACE] = $space[0];
  2055 +
  2056 + // handle empty tags (i.e. "<div/>")
  2057 + if ($this->copy_until_char('>') === '/') {
  2058 + $node->_[HDOM_INFO_ENDSPACE] .= '/';
  2059 + $node->_[HDOM_INFO_END] = 0;
  2060 + } else {
  2061 + // reset parent
  2062 + if (!isset($this->self_closing_tags[strtolower($node->tag)])) {
  2063 + $this->parent = $node;
  2064 + }
  2065 + }
  2066 +
  2067 + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
  2068 +
  2069 + // If it's a BR tag, we need to set it's text to the default text.
  2070 + // This way when we see it in plaintext, we can generate formatting that the user wants.
  2071 + // since a br tag never has sub nodes, this works well.
  2072 + if ($node->tag === 'br') {
  2073 + $node->_[HDOM_INFO_INNER] = $this->default_br_text;
  2074 + }
  2075 +
  2076 + return true;
  2077 + }
  2078 +
  2079 + protected function parse_attr($node, $name, &$space)
  2080 + {
  2081 + $is_duplicate = isset($node->attr[$name]);
  2082 +
  2083 + if (!$is_duplicate) // Copy whitespace between "=" and value
  2084 + $space[2] = $this->copy_skip($this->token_blank);
  2085 +
  2086 + switch ($this->char) {
  2087 + case '"':
  2088 + $quote_type = HDOM_QUOTE_DOUBLE;
  2089 + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
  2090 + $value = $this->copy_until_char('"');
  2091 + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
  2092 + break;
  2093 + case '\'':
  2094 + $quote_type = HDOM_QUOTE_SINGLE;
  2095 + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
  2096 + $value = $this->copy_until_char('\'');
  2097 + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
  2098 + break;
  2099 + default:
  2100 + $quote_type = HDOM_QUOTE_NO;
  2101 + $value = $this->copy_until($this->token_attr);
  2102 + }
  2103 +
  2104 + $value = $this->restore_noise($value);
  2105 +
  2106 + // PaperG: Attributes should not have \r or \n in them, that counts as
  2107 + // html whitespace.
  2108 + $value = str_replace("\r", '', $value);
  2109 + $value = str_replace("\n", '', $value);
  2110 +
  2111 + // PaperG: If this is a "class" selector, lets get rid of the preceeding
  2112 + // and trailing space since some people leave it in the multi class case.
  2113 + if ($name === 'class') {
  2114 + $value = trim($value);
  2115 + }
  2116 +
  2117 + if (!$is_duplicate) {
  2118 + $node->_[HDOM_INFO_QUOTE][] = $quote_type;
  2119 + $node->attr[$name] = $value;
  2120 + }
  2121 + }
  2122 +
  2123 + protected function link_nodes(&$node, $is_child)
  2124 + {
  2125 + $node->parent = $this->parent;
  2126 + $this->parent->nodes[] = $node;
  2127 + if ($is_child) {
  2128 + $this->parent->children[] = $node;
  2129 + }
  2130 + }
  2131 +
  2132 + protected function as_text_node($tag)
  2133 + {
  2134 + $node = new simple_html_dom_node($this);
  2135 + ++$this->cursor;
  2136 + $node->_[HDOM_INFO_TEXT] = '</' . $tag . '>';
  2137 + $this->link_nodes($node, false);
  2138 + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
  2139 + return true;
  2140 + }
  2141 +
  2142 + protected function skip($chars)
  2143 + {
  2144 + $this->pos += strspn($this->doc, $chars, $this->pos);
  2145 + $this->char = ($this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
  2146 + }
  2147 +
  2148 + protected function copy_skip($chars)
  2149 + {
  2150 + $pos = $this->pos;
  2151 + $len = strspn($this->doc, $chars, $pos);
  2152 + $this->pos += $len;
  2153 + $this->char = ($this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
  2154 + if ($len === 0) { return ''; }
  2155 + return substr($this->doc, $pos, $len);
  2156 + }
  2157 +
  2158 + protected function copy_until($chars)
  2159 + {
  2160 + $pos = $this->pos;
  2161 + $len = strcspn($this->doc, $chars, $pos);
  2162 + $this->pos += $len;
  2163 + $this->char = ($this->pos < $this->size) ? $this->doc[$this->pos] : null; // next
  2164 + return substr($this->doc, $pos, $len);
  2165 + }
  2166 +
  2167 + protected function copy_until_char($char)
  2168 + {
  2169 + if ($this->char === null) { return ''; }
  2170 +
  2171 + if (($pos = strpos($this->doc, $char, $this->pos)) === false) {
  2172 + $ret = substr($this->doc, $this->pos, $this->size - $this->pos);
  2173 + $this->char = null;
  2174 + $this->pos = $this->size;
  2175 + return $ret;
  2176 + }
  2177 +
  2178 + if ($pos === $this->pos) { return ''; }
  2179 +
  2180 + $pos_old = $this->pos;
  2181 + $this->char = $this->doc[$pos];
  2182 + $this->pos = $pos;
  2183 + return substr($this->doc, $pos_old, $pos - $pos_old);
  2184 + }
  2185 +
  2186 + protected function remove_noise($pattern, $remove_tag = false)
  2187 + {
  2188 + global $debug_object;
  2189 + if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
  2190 +
  2191 + $count = preg_match_all(
  2192 + $pattern,
  2193 + $this->doc,
  2194 + $matches,
  2195 + PREG_SET_ORDER | PREG_OFFSET_CAPTURE
  2196 + );
  2197 +
  2198 + for ($i = $count - 1; $i > -1; --$i) {
  2199 + $key = '___noise___' . sprintf('% 5d', count($this->noise) + 1000);
  2200 +
  2201 + if (is_object($debug_object)) {
  2202 + $debug_object->debug_log(2, 'key is: ' . $key);
  2203 + }
  2204 +
  2205 + $idx = ($remove_tag) ? 0 : 1; // 0 = entire match, 1 = submatch
  2206 + $this->noise[$key] = $matches[$i][$idx][0];
  2207 + $this->doc = substr_replace($this->doc, $key, $matches[$i][$idx][1], strlen($matches[$i][$idx][0]));
  2208 + }
  2209 +
  2210 + // reset the length of content
  2211 + $this->size = strlen($this->doc);
  2212 +
  2213 + if ($this->size > 0) {
  2214 + $this->char = $this->doc[0];
  2215 + }
  2216 + }
  2217 +
  2218 + function restore_noise($text)
  2219 + {
  2220 + global $debug_object;
  2221 + if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
  2222 +
  2223 + while (($pos = strpos($text, '___noise___')) !== false) {
  2224 + // Sometimes there is a broken piece of markup, and we don't GET the
  2225 + // pos+11 etc... token which indicates a problem outside of us...
  2226 +
  2227 + // todo: "___noise___1000" (or any number with four or more digits)
  2228 + // in the DOM causes an infinite loop which could be utilized by
  2229 + // malicious software
  2230 + if (strlen($text) > $pos + 15) {
  2231 + $key = '___noise___'
  2232 + . $text[$pos + 11]
  2233 + . $text[$pos + 12]
  2234 + . $text[$pos + 13]
  2235 + . $text[$pos + 14]
  2236 + . $text[$pos + 15];
  2237 +
  2238 + if (is_object($debug_object)) {
  2239 + $debug_object->debug_log(2, 'located key of: ' . $key);
  2240 + }
  2241 +
  2242 + if (isset($this->noise[$key])) {
  2243 + $text = substr($text, 0, $pos)
  2244 + . $this->noise[$key]
  2245 + . substr($text, $pos + 16);
  2246 + } else {
  2247 + // do this to prevent an infinite loop.
  2248 + $text = substr($text, 0, $pos)
  2249 + . 'UNDEFINED NOISE FOR KEY: '
  2250 + . $key
  2251 + . substr($text, $pos + 16);
  2252 + }
  2253 + } else {
  2254 + // There is no valid key being given back to us... We must get
  2255 + // rid of the ___noise___ or we will have a problem.
  2256 + $text = substr($text, 0, $pos)
  2257 + . 'NO NUMERIC NOISE KEY'
  2258 + . substr($text, $pos + 11);
  2259 + }
  2260 + }
  2261 + return $text;
  2262 + }
  2263 +
  2264 + function search_noise($text)
  2265 + {
  2266 + global $debug_object;
  2267 + if (is_object($debug_object)) { $debug_object->debug_log_entry(1); }
  2268 +
  2269 + foreach($this->noise as $noiseElement) {
  2270 + if (strpos($noiseElement, $text) !== false) {
  2271 + return $noiseElement;
  2272 + }
  2273 + }
  2274 + }
  2275 +
  2276 + function __toString()
  2277 + {
  2278 + return $this->root->innertext();
  2279 + }
  2280 +
  2281 + function __get($name)
  2282 + {
  2283 + switch ($name) {
  2284 + case 'outertext':
  2285 + return $this->root->innertext();
  2286 + case 'innertext':
  2287 + return $this->root->innertext();
  2288 + case 'plaintext':
  2289 + return $this->root->text();
  2290 + case 'charset':
  2291 + return $this->_charset;
  2292 + case 'target_charset':
  2293 + return $this->_target_charset;
  2294 + }
  2295 + }
  2296 +
  2297 + function childNodes($idx = -1)
  2298 + {
  2299 + return $this->root->childNodes($idx);
  2300 + }
  2301 +
  2302 + function firstChild()
  2303 + {
  2304 + return $this->root->first_child();
  2305 + }
  2306 +
  2307 + function lastChild()
  2308 + {
  2309 + return $this->root->last_child();
  2310 + }
  2311 +
  2312 + function createElement($name, $value = null)
  2313 + {
  2314 + return @str_get_html("<$name>$value</$name>")->firstChild();
  2315 + }
  2316 +
  2317 + function createTextNode($value)
  2318 + {
  2319 + return @end(str_get_html($value)->nodes);
  2320 + }
  2321 +
  2322 + function getElementById($id)
  2323 + {
  2324 + return $this->find("#$id", 0);
  2325 + }
  2326 +
  2327 + function getElementsById($id, $idx = null)
  2328 + {
  2329 + return $this->find("#$id", $idx);
  2330 + }
  2331 +
  2332 + function getElementByTagName($name)
  2333 + {
  2334 + return $this->find($name, 0);
  2335 + }
  2336 +
  2337 + function getElementsByTagName($name, $idx = -1)
  2338 + {
  2339 + return $this->find($name, $idx);
  2340 + }
  2341 +
  2342 + function loadFile()
  2343 + {
  2344 + $args = func_get_args();
  2345 + $this->load_file($args);
  2346 + }
  2347 +}
... ...
php/config.php
... ... @@ -183,7 +183,7 @@ $API = array(
183 183 //AKKA - New action to clean user WS
184 184 'cleanUserWS'=>array('len'=>0),
185 185 'deleteSpecialInfo'=>array('len'=>1),
186   - 'interactivePlot'=>array('len'=>2),
  186 + 'interactivePlot'=>array('len'=>1),
187 187 'getParamPlotInit'=>array('len'=>1),
188 188 'getParamInfo'=>array('len'=>1),
189 189 'getDerivedParamInfo'=>array('len'=>1),
... ...
php/downloadPlot.php
... ... @@ -10,19 +10,19 @@ if (!isset($_POST[&#39;sessionId&#39;]))
10 10 }
11 11 $sessionId = $_POST['sessionId'];
12 12  
13   -if (!isset($_POST['tabId']))
  13 +if (!isset($_POST['interactiveId']))
14 14 {
15 15 header("HTTP/1.0 400 Bad Request");
16   - echo json_encode(array("success" => false, "error" => "Unknown tab Id"));
  16 + echo json_encode(array("success" => false, "error" => "Unknown interactive Id"));
17 17 exit;
18 18 }
19   -$tabId = $_POST['tabId'];
  19 +$interactiveId = $_POST['interactiveId'];
20 20  
21 21 $preview = empty($_POST['preview']) ? FALSE : $_POST['preview'];
22 22  
23   -download_plot($sessionId, $tabId, $preview);
  23 +download_plot($sessionId, $interactiveId, $preview);
24 24  
25   -function download_plot($sessionId, $tabId, $preview)
  25 +function download_plot($sessionId, $interactiveId, $preview)
26 26 {
27 27 // Must be fresh start
28 28 if( headers_sent() )
... ... @@ -38,10 +38,10 @@ function download_plot($sessionId, $tabId, $preview)
38 38  
39 39 //Build file path
40 40 if (!$preview) {
41   - $fullPath = USERPATH."/".$sessionId."/RES/Plot_/".$tabId.".png";
  41 + $fullPath = USERPATH."/".$sessionId."/RES/Plot_/".$interactiveId.".png";
42 42 }
43 43 else {
44   - $fullPath = USERPATH."/".$sessionId."/RES/Plot_/".str_replace('plot_','instant',$tabId).".png";
  44 + $fullPath = USERPATH."/".$sessionId."/RES/Plot_/".str_replace('plot_','instant',$interactiveId).".png";
45 45 }
46 46 // File Exists?
47 47 if( file_exists($fullPath) ){
... ...
php/src/cdfsamplingfromdata.c
... ... @@ -126,7 +126,7 @@ int main(int argc, char *argv[])
126 126 if (datatype == CDF_TIME_TT2000) {
127 127 dbl_value_ = CDF_TT2000_to_UTC_EPOCH(int_value[0]);
128 128 dbl_value = CDF_TT2000_to_UTC_EPOCH(int_value[1]);
129   - sampling = (int)(dbl_value - dbl_value_ + 50)/100;
  129 + sampling = (int)(dbl_value - dbl_value_);
130 130 }
131 131 else {
132 132 if (datatype == CDF_EPOCH16) {
... ... @@ -139,7 +139,7 @@ int main(int argc, char *argv[])
139 139 EPOCH16breakdown(epoch16, &year, &month, &day, &hour, &minute, &sec, &msec, &mksec, &nsec, &psec);
140 140 value[1] = computeEPOCH(year, month, day, hour, minute, sec, msec);
141 141 }
142   - sampling = (int)(value[1] - value[0] + 50)/100;
  142 + sampling = (int)(value[1] - value[0]);
143 143 }
144 144  
145 145 // fprintf(stdout,"value %f\n", value[11]-value[10]);
... ... @@ -150,5 +150,5 @@ int main(int argc, char *argv[])
150 150 if ((cstatus = CDFlib(CLOSE_, CDF_, NULL_)) != CDF_OK)
151 151 cdf_handle_error (cstatus);
152 152  
153   - fprintf(stdout,"%f\n",(float)sampling/10.0);
  153 + fprintf(stdout,"%f\n",(float)sampling/1000.0); // in sec.msec
154 154 }
... ...
php/src/cdfsamplingsfromdata.c
... ... @@ -162,7 +162,7 @@ int main(int argc, char *argv[])
162 162 if (datatype == CDF_TIME_TT2000) {
163 163 dbl_value_ = CDF_TT2000_to_UTC_EPOCH(int_value[i-1]);
164 164 dbl_value = CDF_TT2000_to_UTC_EPOCH(int_value[i]);
165   - delta[i-1] = (int)(dbl_value - dbl_value_ + 50)/100;
  165 + delta[i-1] = (int)(dbl_value - dbl_value_);
166 166 }
167 167 else {
168 168 if (datatype == CDF_EPOCH16) {
... ... @@ -175,7 +175,7 @@ int main(int argc, char *argv[])
175 175 EPOCH16breakdown(epoch16, &year, &month, &day, &hour, &minute, &sec, &msec, &mksec, &nsec, &psec);
176 176 value[i] = computeEPOCH(year, month, day, hour, minute, sec, msec);
177 177 }
178   - delta[i-1] = (int)(value[i] - value[i-1] + 50)/100;
  178 + delta[i-1] = (int)(value[i] - value[i-1]);
179 179 }
180 180 }
181 181 // fprintf(stdout,"value %f\n", value[11]-value[10]);
... ... @@ -194,5 +194,5 @@ int main(int argc, char *argv[])
194 194 cdf_handle_error (cstatus);
195 195  
196 196 // fprintf(stdout,"%d %f\n",min[1], (float)min[0]/100.0);
197   - fprintf(stdout,"%f\n",(float)min[0]/10.0);
  197 + fprintf(stdout,"%f\n",(float)min[0]/1000.0);
198 198 }
... ...