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 <li>1. To plot a parameter <i>drag</i> it from the Parameters tree and <i>drop</i> onto the panel 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 \ No newline at end of file 5 \ No newline at end of file
js/app/controllers/InteractiveModule.js
@@ -37,12 +37,15 @@ Ext.define(&#39;amdaDesktop.InteractiveModule&#39;, { @@ -37,12 +37,15 @@ Ext.define(&#39;amdaDesktop.InteractiveModule&#39;, {
37 /** 37 /**
38 * Window Creation method of the Module 38 * Window Creation method of the Module
39 */ 39 */
40 - createWindow : function (onShowEvent) { 40 + createWindow : function (onShowEvent, onAfterCreateObject) {
41 41
42 if (this.linkedNode === null){ 42 if (this.linkedNode === null){
43 this.createLinkedNode(); 43 this.createLinkedNode();
44 } 44 }
45 - this.createObject(); 45 + this.createObject();
  46 + if (onAfterCreateObject) {
  47 + onAfterCreateObject();
  48 + }
46 var desktop = this.app.getDesktop(); 49 var desktop = this.app.getDesktop();
47 var win = desktop.getWindow(this.id); 50 var win = desktop.getWindow(this.id);
48 var me = this; 51 var me = this;
js/app/controllers/PlotModule.js
@@ -13,8 +13,8 @@ Ext.define(&#39;amdaDesktop.PlotModule&#39;, { @@ -13,8 +13,8 @@ Ext.define(&#39;amdaDesktop.PlotModule&#39;, {
13 13
14 requires: [ 14 requires: [
15 'amdaUI.PlotUI', 15 'amdaUI.PlotUI',
16 - 'amdaPlotObj.PlotRequestObject',  
17 - 'amdaModel.PlotNode', 16 + 'amdaPlotObj.MultiplotRequestObject',
  17 + 'amdaModel.MultiplotNode',
18 'amdaUI.PlotTabResultUI', 18 'amdaUI.PlotTabResultUI',
19 'amdaPlotComp.PlotPreviewUI' 19 'amdaPlotComp.PlotPreviewUI'
20 ], 20 ],
@@ -26,7 +26,7 @@ Ext.define(&#39;amdaDesktop.PlotModule&#39;, { @@ -26,7 +26,7 @@ Ext.define(&#39;amdaDesktop.PlotModule&#39;, {
26 * @cfg {String} data models 26 * @cfg {String} data models
27 * @required 27 * @required
28 */ 28 */
29 - nodeDataModel : 'amdaModel.PlotNode', 29 + nodeDataModel : 'amdaModel.MultiplotNode',
30 30
31 /** 31 /**
32 * @cfg {String} window definitions 32 * @cfg {String} window definitions
@@ -40,173 +40,197 @@ Ext.define(&#39;amdaDesktop.PlotModule&#39;, { @@ -40,173 +40,197 @@ Ext.define(&#39;amdaDesktop.PlotModule&#39;, {
40 40
41 plotResultWindowsManager : new Ext.AbstractManager(), 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 updateInteractiveSession : function(session, newplot) { 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 closeInteractiveSession : function() { 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 updatePreview : function(plotPreviewConfig) { 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 getWindowResult: function(winResultId){ 187 getWindowResult: function(winResultId){
209 if (!this.plotResultWindowsManager.get(winResultId)) return null; 188 if (!this.plotResultWindowsManager.get(winResultId)) return null;
210 return this.plotResultWindowsManager.get(winResultId); 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,20 +128,7 @@ Ext.define(&#39;amdaModel.AmdaNode&#39;, {
128 } 128 }
129 // if this node is a leaf and have no child 129 // if this node is a leaf and have no child
130 else if (this.isLeaf() || this.get('nodeType' ) == 'derivedParam' ) { 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 else if (this.get('isParameter') && this.get('nodeType' ) != 'derivedParam' ) { 133 else if (this.get('isParameter') && this.get('nodeType' ) != 'derivedParam' ) {
147 itemKind = amdaUI.ExplorerUI.ITEM_KIND_PARA; 134 itemKind = amdaUI.ExplorerUI.ITEM_KIND_PARA;
js/app/models/AmdaTimeObject.js
@@ -7,11 +7,7 @@ @@ -7,11 +7,7 @@
7 * 7 *
8 * @author elena 8 * @author elena
9 * @version $Id: AmdaTimeObject.js 1534 2013-05-24 13:30:26Z myriam $ 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,66 +22,70 @@ Ext.define(&#39;amdaModel.TTobject&#39;, {
26 } 22 }
27 }); 23 });
28 24
29 -  
30 Ext.define('amdaModel.AmdaTimeObject', { 25 Ext.define('amdaModel.AmdaTimeObject', {
31 extend: 'amdaModel.AmdaObject', 26 extend: 'amdaModel.AmdaObject',
32 statics:{ 27 statics:{
33 inputTimeSrc: ['TimeTable','Interval','Catalog'] 28 inputTimeSrc: ['TimeTable','Interval','Catalog']
34 - }, 29 + },
35 fields : [ 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,9 +10,6 @@
10 10
11 Ext.define('amdaModel.BkgJobNode', { 11 Ext.define('amdaModel.BkgJobNode', {
12 extend: 'amdaModel.ExecutableNode', 12 extend: 'amdaModel.ExecutableNode',
13 - requires: [  
14 - 'amdaPlotObj.PlotRequestObject'  
15 - ],  
16 action : null, 13 action : null,
17 14
18 statics: { 15 statics: {
js/app/models/DownloadNode.js
@@ -62,90 +62,74 @@ Ext.define(&#39;amdaModel.DownloadNode&#39;, { @@ -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 encodeObject: function() { 134 encodeObject: function() {
151 }, 135 },
js/app/models/InteractiveNode.js
@@ -11,10 +11,6 @@ @@ -11,10 +11,6 @@
11 Ext.define('amdaModel.InteractiveNode', { 11 Ext.define('amdaModel.InteractiveNode', {
12 extend: 'amdaModel.AmdaNode', 12 extend: 'amdaModel.AmdaNode',
13 13
14 - requires: [  
15 - 'amdaPlotObj.PlotRequestObject'  
16 - ],  
17 -  
18 fields: [ 14 fields: [
19 {name: 'contextNode', type: 'amdaModel.AmdaNode', persist: false}, 15 {name: 'contextNode', type: 'amdaModel.AmdaNode', persist: false},
20 {name: 'objectDataModel', type: 'string', persist: false}, 16 {name: 'objectDataModel', type: 'string', persist: false},
@@ -52,7 +48,7 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, { @@ -52,7 +48,7 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, {
52 { 48 {
53 node.eachChild(function(n) 49 node.eachChild(function(n)
54 { 50 {
55 - if (!n.isLoaded() && !n.isRealLeaf()) 51 + if (!n.isLoaded() && !n.isLeaf())
56 { 52 {
57 nodesToLoad.push(n); 53 nodesToLoad.push(n);
58 me.preloadTreeNode(n,nodesToLoad,onloaded); 54 me.preloadTreeNode(n,nodesToLoad,onloaded);
@@ -70,7 +66,7 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, { @@ -70,7 +66,7 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, {
70 { 66 {
71 records.forEach(function (record) 67 records.forEach(function (record)
72 { 68 {
73 - if (!record.isLoaded() && !record.isRealLeaf()) 69 + if (!record.isLoaded() && !record.isLeaf())
74 { 70 {
75 nodesToLoad.push(record); 71 nodesToLoad.push(record);
76 me.preloadTreeNode(record,nodesToLoad,onloaded); 72 me.preloadTreeNode(record,nodesToLoad,onloaded);
@@ -100,11 +96,6 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, { @@ -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 * this method is overriden into ExecutableNode to return true 100 * this method is overriden into ExecutableNode to return true
110 */ 101 */
@@ -151,7 +142,7 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, { @@ -151,7 +142,7 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, {
151 */ 142 */
152 rename: function(value,callBackFn) 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 AmdaAction.renameObject(dataToSend, callBackFn); 146 AmdaAction.renameObject(dataToSend, callBackFn);
156 }, 147 },
157 148
@@ -160,7 +151,7 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, { @@ -160,7 +151,7 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, {
160 */ 151 */
161 renameDD: function(parentId, callBackFn) 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 AmdaAction.renameObject(dataToSend, callBackFn); 155 AmdaAction.renameObject(dataToSend, callBackFn);
165 }, 156 },
166 157
@@ -171,7 +162,7 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, { @@ -171,7 +162,7 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, {
171 */ 162 */
172 isValidName : function(name, callBackFn) 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 AmdaAction.validNameObject(dataToSend, callBackFn); 166 AmdaAction.validNameObject(dataToSend, callBackFn);
176 }, 167 },
177 168
@@ -219,7 +210,12 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, { @@ -219,7 +210,12 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, {
219 // reload object into the view of corresponding Module 210 // reload object into the view of corresponding Module
220 var me = this; 211 var me = this;
221 myDesktopApp.getLoadedModule(this.get('moduleId'), true, function (module) { 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 else { 221 else {
@@ -459,16 +455,7 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, { @@ -459,16 +455,7 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, {
459 { 455 {
460 if (node.get('disable')) return; 456 if (node.get('disable')) return;
461 myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.plot.id, true, function (module) { 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,7 +517,7 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, {
530 517
531 deleteNode: function() { 518 deleteNode: function() {
532 // if the target is a directory 519 // if the target is a directory
533 - if (!this.isRealLeaf()) { 520 + if (!this.isLeaf()) {
534 // determine if this directory is empty before launching the delete confirmation method 521 // determine if this directory is empty before launching the delete confirmation method
535 this.isNotEmptyDir(this.confirmDirectoryDeletion); 522 this.isNotEmptyDir(this.confirmDirectoryDeletion);
536 // else (the target is a leaf) 523 // else (the target is a leaf)
@@ -583,14 +570,14 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, { @@ -583,14 +570,14 @@ Ext.define(&#39;amdaModel.InteractiveNode&#39;, {
583 */ 570 */
584 realDelete : function() 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 //TODO proper errors handling 574 //TODO proper errors handling
588 // node deletion in tree 575 // node deletion in tree
589 if (res) { // if success 576 if (res) { // if success
590 if (res.id) { 577 if (res.id) {
591 //Ext.Msg.show({title:'Warning', msg: 'Requests with parameter '+node.data.text+' are deleted', icon: Ext.MessageBox.ERROR, buttons: Ext.Msg.OK}); 578 //Ext.Msg.show({title:'Warning', msg: 'Requests with parameter '+node.data.text+' are deleted', icon: Ext.MessageBox.ERROR, buttons: Ext.Msg.OK});
592 if (this.parentNode) { 579 if (this.parentNode) {
593 - if (this.isRealLeaf()){ 580 + if (this.isLeaf()){
594 var moduleId = this.get('moduleId'); 581 var moduleId = this.get('moduleId');
595 // if really interactive node 582 // if really interactive node
596 if (moduleId) { 583 if (moduleId) {
js/app/models/MultiplotNode.js 0 โ†’ 100644
@@ -0,0 +1,25 @@ @@ -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,49 +8,17 @@
8 */ 8 */
9 9
10 Ext.define('amdaModel.PlotNode', { 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 statics: { 13 statics: {
18 nodeType: 'request' 14 nodeType: 'request'
19 }, 15 },
20 16
21 - requires:[  
22 - 'amdaModel.PlotTabNode'  
23 - ],  
24 -  
25 constructor : function(config){ 17 constructor : function(config){
26 this.callParent(arguments); 18 this.callParent(arguments);
27 this.set('moduleId',myDesktopApp.dynamicModules.plot.id); 19 this.set('moduleId',myDesktopApp.dynamicModules.plot.id);
28 this.set('objectDataModel','amdaPlotObj.PlotRequestObject'); 20 this.set('objectDataModel','amdaPlotObj.PlotRequestObject');
29 this.set('nodeType',this.self.nodeType); 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 allMenuItems : function() { 24 allMenuItems : function() {
@@ -76,10 +44,6 @@ Ext.define(&#39;amdaModel.PlotNode&#39;, { @@ -76,10 +44,6 @@ Ext.define(&#39;amdaModel.PlotNode&#39;, {
76 }, { 44 }, {
77 fnId : 'leaf-deleteNode', 45 fnId : 'leaf-deleteNode',
78 text : 'Delete Request' 46 text : 'Delete Request'
79 - }, {  
80 - fnId : 'leaf-insertTabs',  
81 - text : 'Insert in current Plot Request'  
82 -  
83 }]; 47 }];
84 48
85 return menuItems; 49 return menuItems;
@@ -128,35 +92,33 @@ Ext.define(&#39;amdaModel.PlotNode&#39;, { @@ -128,35 +92,33 @@ Ext.define(&#39;amdaModel.PlotNode&#39;, {
128 case 'deleteMulti': 92 case 'deleteMulti':
129 this.deleteMulti(); 93 this.deleteMulti();
130 break; 94 break;
131 - case 'insertTabs':  
132 - this.insertPlotTabsRequest();  
133 default: 95 default:
134 break; 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 @@ @@ -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,11 +5,12 @@
5 * @extends amdaModel.AmdaTimeObject 5 * @extends amdaModel.AmdaTimeObject
6 * @brief Plot Request Business Object Definition 6 * @brief Plot Request Business Object Definition
7 * @author Benjamin Renard 7 * @author Benjamin Renard
8 - * @version $Id: PlotRequestObject.js benjamin $ 8 + * @version $Id: PlotTabObject.js benjamin $
9 ****************************************************************************** 9 ******************************************************************************
10 * FT Id : Date : Name - Description 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,122 +20,256 @@ Ext.define(&#39;amdaPlotObj.PlotRequestObject&#39;, {
19 20
20 requires: [ 21 requires: [
21 'amdaPlotObj.PlotObjectConfig', 22 'amdaPlotObj.PlotObjectConfig',
22 - 'amdaPlotObj.PlotTabObject' 23 + 'amdaPlotObj.PlotPanelObject',
  24 + 'amdaPlotObj.PlotLayoutVerticalObject',
  25 + 'amdaPlotObj.PlotLayoutAutoObject',
  26 + 'amdaPlotObj.PlotLayoutManualObject'
23 ], 27 ],
24 28
25 fields : [ 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 {name: 'file-format', type: 'string'}, 33 {name: 'file-format', type: 'string'},
28 {name: 'file-output', type: 'string'}, 34 {name: 'file-output', type: 'string'},
29 {name: 'file-prefix', type: 'string'}, 35 {name: 'file-prefix', type: 'string'},
30 {name: 'one-file-per-interval', type: 'boolean'}, 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 constructor: function(){ 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 else 86 else
51 { 87 {
52 //new object, set default fields values 88 //new object, set default fields values
53 me.setDefaultValues(); 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 this.dirty = true; 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 return false; 120 return false;
96 - this.tabs().remove(tabRecord); 121 + this.panels().remove(panelRecord);
97 this.dirty = true; 122 this.dirty = true;
  123 + this.updatePanelIndex();
98 return true; 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 if (this.dirty) 214 if (this.dirty)
107 return true; 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 var d = false; 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 d = true; 224 d = true;
113 }); 225 });
114 return d; 226 return d;
115 }, 227 },
116 228
117 - getJsonValues : function(hasId) 229 + getJsonValues : function()
118 { 230 {
119 var requestValues = new Object(); 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 // if there's at least one timeTable name into 'timeTables' collection 273 // if there's at least one timeTable name into 'timeTables' collection
139 if (this.get('timesrc') == amdaModel.AmdaTimeObject.inputTimeSrc[0] && this.get('timeTables') && this.get('timeTables').length){ 274 if (this.get('timesrc') == amdaModel.AmdaTimeObject.inputTimeSrc[0] && this.get('timeTables') && this.get('timeTables').length){
140 // get complete timeTables collection 275 // get complete timeTables collection
@@ -152,23 +287,26 @@ Ext.define(&#39;amdaPlotObj.PlotRequestObject&#39;, { @@ -152,23 +287,26 @@ Ext.define(&#39;amdaPlotObj.PlotRequestObject&#39;, {
152 } 287 }
153 }); 288 });
154 } else { 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,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,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,7 +102,6 @@ Ext.define(&#39;amdaUI.ExplorerUI&#39;, {
102 ITEM_KIND_LEAF : 'leaf', 102 ITEM_KIND_LEAF : 'leaf',
103 ITEM_KIND_DIRE : 'dire', 103 ITEM_KIND_DIRE : 'dire',
104 ITEM_KIND_PARA : 'para', 104 ITEM_KIND_PARA : 'para',
105 - ITEM_KIND_PTAB : 'ptab', //plot tab  
106 ITEM_KIND_MISS : 'miss' 105 ITEM_KIND_MISS : 'miss'
107 }, 106 },
108 107
@@ -354,7 +353,6 @@ Ext.define(&#39;amdaUI.ExplorerUI&#39;, { @@ -354,7 +353,6 @@ Ext.define(&#39;amdaUI.ExplorerUI&#39;, {
354 case 'remoteParam' : 353 case 'remoteParam' :
355 case 'remoteSimuParam' : 354 case 'remoteSimuParam' :
356 case 'myData' : 355 case 'myData' :
357 - case 'plottab' :  
358 return false; 356 return false;
359 default : 357 default :
360 if (draggedRecord.data.id == targetNode.data.nodeType+'-treeRootNode') 358 if (draggedRecord.data.id == targetNode.data.nodeType+'-treeRootNode')
@@ -577,7 +575,7 @@ Ext.define(&#39;amdaUI.ExplorerUI&#39;, { @@ -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 switch (record.get('nodeType')) 579 switch (record.get('nodeType'))
582 { 580 {
583 case 'myData' : 581 case 'myData' :
@@ -591,9 +589,6 @@ Ext.define(&#39;amdaUI.ExplorerUI&#39;, { @@ -591,9 +589,6 @@ Ext.define(&#39;amdaUI.ExplorerUI&#39;, {
591 case 'condition' : 589 case 'condition' :
592 record.editLeaf(); 590 record.editLeaf();
593 break; 591 break;
594 - case 'plottab' :  
595 - record.editPlotTab();  
596 - break;  
597 case 'localParam' : 592 case 'localParam' :
598 case 'remoteParam': 593 case 'remoteParam':
599 case 'remoteSimuParam': 594 case 'remoteSimuParam':
@@ -1029,7 +1024,7 @@ Ext.define( &#39;MyTreeEditor&#39;, { @@ -1029,7 +1024,7 @@ Ext.define( &#39;MyTreeEditor&#39;, {
1029 event.record.commit(); 1024 event.record.commit();
1030 var rec = event.record.data; 1025 var rec = event.record.data;
1031 // in case of directory 1026 // in case of directory
1032 - if (!rec.leaf && (rec.nodeType != 'plottab')){ 1027 + if (!rec.leaf){
1033 // set folder's ID returned by server 1028 // set folder's ID returned by server
1034 rec.id = result.id; 1029 rec.id = result.id;
1035 } 1030 }
js/app/views/IntervalUI.js
@@ -125,6 +125,9 @@ Ext.define(&#39;amdaUI.IntervalUI&#39;, { @@ -125,6 +125,9 @@ Ext.define(&#39;amdaUI.IntervalUI&#39;, {
125 if (stop != null && start != null) { 125 if (stop != null && start != null) {
126 if ( stop <= start ) { 126 if ( stop <= start ) {
127 form.findField('stopDate').markInvalid('Stop Time must be after Start Time'); 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 // compute offset 132 // compute offset
130 var zoneOffset = stop.getTimezoneOffset() - start.getTimezoneOffset(); 133 var zoneOffset = stop.getTimezoneOffset() - start.getTimezoneOffset();
@@ -159,6 +162,21 @@ Ext.define(&#39;amdaUI.IntervalUI&#39;, { @@ -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 updateStop: function() { 180 updateStop: function() {
163 var form = this.findParentByType('form').getForm(); 181 var form = this.findParentByType('form').getForm();
164 var start = form.findField('startDate').getValue(); 182 var start = form.findField('startDate').getValue();
js/app/views/PlotComponents/PlotElementPanel.js
@@ -10,6 +10,7 @@ @@ -10,6 +10,7 @@
10 10
11 Ext.define('amdaPlotComp.PlotElementPanel', { 11 Ext.define('amdaPlotComp.PlotElementPanel', {
12 extend: 'Ext.form.Panel', 12 extend: 'Ext.form.Panel',
  13 +
13 14
14 elementFormsManager : new Ext.AbstractManager(), 15 elementFormsManager : new Ext.AbstractManager(),
15 16
js/app/views/PlotComponents/PlotExtendShiftPlug.js
@@ -21,7 +21,7 @@ Ext.define(&#39;amdaPlotComp.PlotExtendShiftPlug&#39;, { @@ -21,7 +21,7 @@ Ext.define(&#39;amdaPlotComp.PlotExtendShiftPlug&#39;, {
21 id: 'plot-extendshift-plug', 21 id: 'plot-extendshift-plug',
22 win : null, 22 win : null,
23 form : null, 23 form : null,
24 - tabId : '', 24 + interactiveId : '',
25 25
26 constructor: function(config) { 26 constructor: function(config) {
27 Ext.apply(this, config); 27 Ext.apply(this, config);
@@ -39,7 +39,7 @@ Ext.define(&#39;amdaPlotComp.PlotExtendShiftPlug&#39;, { @@ -39,7 +39,7 @@ Ext.define(&#39;amdaPlotComp.PlotExtendShiftPlug&#39;, {
39 /** 39 /**
40 * creation of the window 40 * creation of the window
41 */ 41 */
42 - show : function(tabId) { 42 + show : function(interactiveId) {
43 if (!this.win) 43 if (!this.win)
44 { 44 {
45 this.win = new Ext.Window({ 45 this.win = new Ext.Window({
@@ -77,7 +77,7 @@ Ext.define(&#39;amdaPlotComp.PlotExtendShiftPlug&#39;, { @@ -77,7 +77,7 @@ Ext.define(&#39;amdaPlotComp.PlotExtendShiftPlug&#39;, {
77 Ext.PluginManager.register(this); 77 Ext.PluginManager.register(this);
78 } 78 }
79 79
80 - this.tabId = tabId; 80 + this.interactiveId = interactiveId;
81 this.win.show(); 81 this.win.show();
82 this.win.setPosition(0,0); 82 this.win.setPosition(0,0);
83 }, 83 },
@@ -111,7 +111,7 @@ Ext.define(&#39;amdaPlotComp.PlotExtendShiftPlug&#39;, { @@ -111,7 +111,7 @@ Ext.define(&#39;amdaPlotComp.PlotExtendShiftPlug&#39;, {
111 var durationUnitField = this.form.getForm().findField('durationUnit'); 111 var durationUnitField = this.form.getForm().findField('durationUnit');
112 var duration = this.toSec(durationField.getValue(), durationUnitField.getValue()); 112 var duration = this.toSec(durationField.getValue(), durationUnitField.getValue());
113 if (duration) { 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 else 116 else
117 myDesktopApp.errorMsg('No duration defined'); 117 myDesktopApp.errorMsg('No duration defined');
@@ -190,4 +190,4 @@ Ext.define(&#39;amdaPlotComp.PlotExtendShiftPlug&#39;, { @@ -190,4 +190,4 @@ Ext.define(&#39;amdaPlotComp.PlotExtendShiftPlug&#39;, {
190 }); 190 });
191 return this.form; 191 return this.form;
192 } 192 }
193 -});  
194 \ No newline at end of file 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,7 +80,7 @@ Ext.define(&#39;amdaPlotComp.PlotPreviewUI&#39;, {
80 var me = this; 80 var me = this;
81 81
82 this.crtContext = configResult.context; 82 this.crtContext = configResult.context;
83 - this.tabId = configResult.tabId; 83 + this.interactiveId = configResult.interactiveId;
84 84
85 this.sliderPage = new Ext.slider.Single({ 85 this.sliderPage = new Ext.slider.Single({
86 width: 130, 86 width: 130,
@@ -136,7 +136,7 @@ Ext.define(&#39;amdaPlotComp.PlotPreviewUI&#39;, { @@ -136,7 +136,7 @@ Ext.define(&#39;amdaPlotComp.PlotPreviewUI&#39;, {
136 me.hiddenForm.getForm().submit({ 136 me.hiddenForm.getForm().submit({
137 params: { 137 params: {
138 sessionId: sessionID, 138 sessionId: sessionID,
139 - tabId : me.tabId, 139 + interactiveId : me.interactiveId,
140 preview: true 140 preview: true
141 }, 141 },
142 success: function(form, action) {}, 142 success: function(form, action) {},
js/app/views/PlotComponents/PlotStandardForm.js
@@ -87,7 +87,6 @@ Ext.define(&#39;amdaPlotComp.PlotStandardForm&#39;, { @@ -87,7 +87,6 @@ Ext.define(&#39;amdaPlotComp.PlotStandardForm&#39;, {
87 allowBlank = (typeof allowBlank !== 'undefined') ? allowBlank : false; 87 allowBlank = (typeof allowBlank !== 'undefined') ? allowBlank : false;
88 88
89 return { 89 return {
90 - id:name,  
91 xtype: 'numberfield', 90 xtype: 'numberfield',
92 name: name, 91 name: name,
93 fieldLabel: label, 92 fieldLabel: label,
@@ -112,7 +111,6 @@ Ext.define(&#39;amdaPlotComp.PlotStandardForm&#39;, { @@ -112,7 +111,6 @@ Ext.define(&#39;amdaPlotComp.PlotStandardForm&#39;, {
112 allowBlank = (typeof allowBlank !== 'undefined') ? allowBlank : false; 111 allowBlank = (typeof allowBlank !== 'undefined') ? allowBlank : false;
113 112
114 return { 113 return {
115 - id:name,  
116 xtype: 'textfield', 114 xtype: 'textfield',
117 name: name, 115 name: name,
118 fieldLabel: label, 116 fieldLabel: label,
js/app/views/PlotComponents/PlotTabContent.js
@@ -9,86 +9,242 @@ @@ -9,86 +9,242 @@
9 */ 9 */
10 10
11 Ext.define('amdaPlotComp.PlotTabContent', { 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 constructor: function(config) { 35 constructor: function(config) {
34 this.init(config); 36 this.init(config);
35 this.callParent(arguments); 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 \ No newline at end of file 249 \ No newline at end of file
  250 + }
  251 +});
js/app/views/PlotComponents/PlotTabPanel.js
@@ -9,206 +9,178 @@ @@ -9,206 +9,178 @@
9 */ 9 */
10 10
11 Ext.define('amdaPlotComp.PlotTabPanel', { 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 //Link to the Plot UI 18 //Link to the Plot UI
22 plotUI : null, 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,7 +18,6 @@ Ext.define(&#39;amdaPlotComp.PlotTree&#39;, {
18 //Link to the combo box to define the use of the simplified view 18 //Link to the combo box to define the use of the simplified view
19 simplifiedViewCombo : null, 19 simplifiedViewCombo : null,
20 20
21 - //Link to the combo to attach the tab to the multi plot mode  
22 21
23 //Link to the Plot Element Panel 22 //Link to the Plot Element Panel
24 plotElementPanel: null, 23 plotElementPanel: null,
@@ -63,7 +62,6 @@ Ext.define(&#39;amdaPlotComp.PlotTree&#39;, { @@ -63,7 +62,6 @@ Ext.define(&#39;amdaPlotComp.PlotTree&#39;, {
63 this.suspendLayouts(); 62 this.suspendLayouts();
64 this.buildPanelsNode(); 63 this.buildPanelsNode();
65 this.simplifiedViewCombo.setValue(this.tabObject.get('tree-full-view')); 64 this.simplifiedViewCombo.setValue(this.tabObject.get('tree-full-view'));
66 - this.linkToMultiPlotCombo.setValue(this.tabObject.get('multi-plot-linked'));  
67 this.resumeLayouts(true); 65 this.resumeLayouts(true);
68 }, 66 },
69 67
@@ -853,10 +851,6 @@ Ext.define(&#39;amdaPlotComp.PlotTree&#39;, { @@ -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 init : function(config) { 854 init : function(config) {
861 var me = this; 855 var me = this;
862 856
@@ -891,21 +885,6 @@ Ext.define(&#39;amdaPlotComp.PlotTree&#39;, { @@ -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 var myConf = { 888 var myConf = {
910 store: store, 889 store: store,
911 rootVisible: false, 890 rootVisible: false,
@@ -959,8 +938,6 @@ Ext.define(&#39;amdaPlotComp.PlotTree&#39;, { @@ -959,8 +938,6 @@ Ext.define(&#39;amdaPlotComp.PlotTree&#39;, {
959 scope: this 938 scope: this
960 }, 939 },
961 '-', '->', 940 '-', '->',
962 - this.linkToMultiPlotCombo,  
963 - ' ',  
964 this.simplifiedViewCombo 941 this.simplifiedViewCombo
965 ] 942 ]
966 }; 943 };
js/app/views/PlotComponents/PlotZoomPlug.js
@@ -26,7 +26,7 @@ Ext.define(&#39;amdaPlotComp.PlotZoomPlug&#39;, { @@ -26,7 +26,7 @@ Ext.define(&#39;amdaPlotComp.PlotZoomPlug&#39;, {
26 win: null, 26 win: null,
27 form: null, 27 form: null,
28 zoomType: '', 28 zoomType: '',
29 - tabId: '', 29 + interactiveId: '',
30 panelId: -1, 30 panelId: -1,
31 31
32 linkedTTCatNode: null, 32 linkedTTCatNode: null,
@@ -101,7 +101,7 @@ Ext.define(&#39;amdaPlotComp.PlotZoomPlug&#39;, { @@ -101,7 +101,7 @@ Ext.define(&#39;amdaPlotComp.PlotZoomPlug&#39;, {
101 /** 101 /**
102 * creation of the window 102 * creation of the window
103 */ 103 */
104 - show: function (tabId, zoomType, panelId) { 104 + show: function (interactiveId, zoomType, panelId) {
105 if (!this.win) { 105 if (!this.win) {
106 this.win = new Ext.Window({ 106 this.win = new Ext.Window({
107 id: 'plot-zoom-win-' + this.hostCmp.ownerCt.getId(), // Plot window ID 107 id: 'plot-zoom-win-' + this.hostCmp.ownerCt.getId(), // Plot window ID
@@ -136,7 +136,7 @@ Ext.define(&#39;amdaPlotComp.PlotZoomPlug&#39;, { @@ -136,7 +136,7 @@ Ext.define(&#39;amdaPlotComp.PlotZoomPlug&#39;, {
136 Ext.PluginManager.register(this); 136 Ext.PluginManager.register(this);
137 } 137 }
138 138
139 - this.tabId = tabId; 139 + this.interactiveId = interactiveId;
140 this.updateWinByType(zoomType, panelId); 140 this.updateWinByType(zoomType, panelId);
141 this.win.show(); 141 this.win.show();
142 this.win.setPosition(0, 0); 142 this.win.setPosition(0, 0);
@@ -407,7 +407,7 @@ Ext.define(&#39;amdaPlotComp.PlotZoomPlug&#39;, { @@ -407,7 +407,7 @@ Ext.define(&#39;amdaPlotComp.PlotZoomPlug&#39;, {
407 407
408 this.hostCmp.callInteractivePlot({ 408 this.hostCmp.callInteractivePlot({
409 'action': 'zoom', 409 'action': 'zoom',
410 - 'tabId': this.tabId, 410 + 'interactiveId': this.interactiveId,
411 'panelId': this.panelId, 411 'panelId': this.panelId,
412 'axeId': this.zoomType, 412 'axeId': this.zoomType,
413 'min': minZoom, 413 'min': minZoom,
@@ -423,7 +423,7 @@ Ext.define(&#39;amdaPlotComp.PlotZoomPlug&#39;, { @@ -423,7 +423,7 @@ Ext.define(&#39;amdaPlotComp.PlotZoomPlug&#39;, {
423 handler: function () { 423 handler: function () {
424 this.hostCmp.callInteractivePlot({ 424 this.hostCmp.callInteractivePlot({
425 'action': 'undozoom', 425 'action': 'undozoom',
426 - 'tabId': this.tabId, 426 + 'interactiveId': this.interactiveId,
427 'panelId': this.panelId, 427 'panelId': this.panelId,
428 'axeId': this.zoomType 428 'axeId': this.zoomType
429 }); 429 });
js/app/views/PlotTabResultUI.js
@@ -22,8 +22,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, { @@ -22,8 +22,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
22 22
23 panelImage : null, 23 panelImage : null,
24 crtContext : null, 24 crtContext : null,
25 - tabId : '',  
26 - multiPlotCheck : null, 25 + interactiveId : '',
27 navToolBar : null, 26 navToolBar : null,
28 isTTNavBar : false, 27 isTTNavBar : false,
29 crtTTFileIndex : 0, 28 crtTTFileIndex : 0,
@@ -55,12 +54,6 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, { @@ -55,12 +54,6 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
55 return 'data/'+sessionID +'/RES/'+resultFolder+ '/' + plotFile; 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 toPixelOnSourceImage : function(value) { 57 toPixelOnSourceImage : function(value) {
65 return value*100/this.sliderPage.getValue(); 58 return value*100/this.sliderPage.getValue();
66 }, 59 },
@@ -147,7 +140,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, { @@ -147,7 +140,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
147 me.contextualMenu.add({ 140 me.contextualMenu.add({
148 text:'Zoom on Time Axis', 141 text:'Zoom on Time Axis',
149 handler : function(item, e) { 142 handler : function(item, e) {
150 - zoomPlugin.show(me.tabId, axis.id, panelContext.id); 143 + zoomPlugin.show(me.interactiveId, axis.id, panelContext.id);
151 zoomPlugin.resetMinMaxValue(); 144 zoomPlugin.resetMinMaxValue();
152 me.panelImage.startZoom(true, 0/*me.toPixelOnResultImage(panelContext.y)*/, size.height /*me.toPixelOnResultImage(panelContext.height)*/, onMinTimeSelection, onMaxTimeSelection); 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,7 +149,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
156 insertIntervalItem = { 149 insertIntervalItem = {
157 text:'Insert Interval in TimeTable or Catalog', 150 text:'Insert Interval in TimeTable or Catalog',
158 handler : function(item, e) { 151 handler : function(item, e) {
159 - zoomPlugin.show(me.tabId, axis.id, panelContext.id); 152 + zoomPlugin.show(me.interactiveId, axis.id, panelContext.id);
160 zoomPlugin.resetMinMaxValue(); 153 zoomPlugin.resetMinMaxValue();
161 me.panelImage.startZoom(true, 0/*me.toPixelOnResultImage(panelContext.y)*/, size.height /*me.toPixelOnResultImage(panelContext.height)*/, onMinTimeSelection, onMaxTimeSelection); 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,7 +160,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
167 me.contextualMenu.add({ 160 me.contextualMenu.add({
168 text:'Zoom on Y Left Axis', 161 text:'Zoom on Y Left Axis',
169 handler : function(item, e) { 162 handler : function(item, e) {
170 - zoomPlugin.show(me.tabId, axis.id, panelContext.id); 163 + zoomPlugin.show(me.interactiveId, axis.id, panelContext.id);
171 zoomPlugin.resetMinMaxValue(); 164 zoomPlugin.resetMinMaxValue();
172 me.panelImage.startZoom(false, me.toPixelOnResultImage(panelContext.x), me.toPixelOnResultImage(panelContext.width), onMinYValueSelection, onMaxYValueSelection); 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,7 +170,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
177 me.contextualMenu.add({ 170 me.contextualMenu.add({
178 text:'Zoom on Y Right Axis', 171 text:'Zoom on Y Right Axis',
179 handler : function(item, e) { 172 handler : function(item, e) {
180 - zoomPlugin.show(me.tabId, axis.id, panelContext.id); 173 + zoomPlugin.show(me.interactiveId, axis.id, panelContext.id);
181 zoomPlugin.resetMinMaxValue(); 174 zoomPlugin.resetMinMaxValue();
182 me.panelImage.startZoom(false, me.toPixelOnResultImage(panelContext.x), me.toPixelOnResultImage(panelContext.width), onMinYValueSelection, onMaxYValueSelection); 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,7 +180,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
187 me.contextualMenu.add({ 180 me.contextualMenu.add({
188 text:'Zoom on X Axis', 181 text:'Zoom on X Axis',
189 handler : function(item, e) { 182 handler : function(item, e) {
190 - zoomPlugin.show(me.tabId, axis.id, panelContext.id); 183 + zoomPlugin.show(me.interactiveId, axis.id, panelContext.id);
191 zoomPlugin.resetMinMaxValue(); 184 zoomPlugin.resetMinMaxValue();
192 me.panelImage.startZoom(true, me.toPixelOnResultImage(panelContext.y), me.toPixelOnResultImage(panelContext.height), onMinXValueSelection, onMaxXValueSelection); 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,6 +198,11 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
205 me.contextualMenu.add(insertIntervalItem); 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 createPlotImage: function(resultFolder, plotFile) { 207 createPlotImage: function(resultFolder, plotFile) {
210 var me = this; 208 var me = this;
@@ -259,16 +257,16 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, { @@ -259,16 +257,16 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
259 xText = crtTime.toJSON(); 257 xText = crtTime.toJSON();
260 break; 258 break;
261 case 'y-left' : 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 break; 261 break;
264 case 'y-right' : 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 break; 264 break;
267 case 'xaxis_id' : 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 break; 267 break;
270 case 'epochAxis' : 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 break; 270 break;
273 } 271 }
274 272
@@ -312,7 +310,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, { @@ -312,7 +310,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
312 var crtTimestamp = amdaPlotComp.PlotContextManager.toAxisValue(timeAxisContext, panel.plotArea.x, panel.plotArea.x+panel.plotArea.width, sourceXPos); 310 var crtTimestamp = amdaPlotComp.PlotContextManager.toAxisValue(timeAxisContext, panel.plotArea.x, panel.plotArea.x+panel.plotArea.width, sourceXPos);
313 var crtTime = new Date(crtTimestamp*1000); 311 var crtTime = new Date(crtTimestamp*1000);
314 crtTime = Ext.Date.add(crtTime, Ext.Date.MINUTE, crtTime.getTimezoneOffset()); 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 scope: me 315 scope: me
318 }, 316 },
@@ -333,7 +331,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, { @@ -333,7 +331,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
333 handler : function () 331 handler : function ()
334 { 332 {
335 var extendShiftPlugin = this.getPlugin('plot-extendshift-plugin-id'); 333 var extendShiftPlugin = this.getPlugin('plot-extendshift-plugin-id');
336 - extendShiftPlugin.show(me.tabId); 334 + extendShiftPlugin.show(me.interactiveId);
337 }, 335 },
338 scope: me 336 scope: me
339 }, 337 },
@@ -358,7 +356,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, { @@ -358,7 +356,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
358 me.hiddenForm.getForm().submit({ 356 me.hiddenForm.getForm().submit({
359 params: { 357 params: {
360 sessionId: sessionID, 358 sessionId: sessionID,
361 - tabId : me.tabId 359 + interactiveId : me.interactiveId
362 }, 360 },
363 success: function(form, action) {}, 361 success: function(form, action) {},
364 failure: function(form, action) {} 362 failure: function(form, action) {}
@@ -388,13 +386,6 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, { @@ -388,13 +386,6 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
388 386
389 this.updateTimeTableInfo(); 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 this.panelImage.setSrc(this.getImageUrl(configResult.folder, configResult.plotFile)); 389 this.panelImage.setSrc(this.getImageUrl(configResult.folder, configResult.plotFile));
399 390
400 var size = this.getImageSize(); 391 var size = this.getImageSize();
@@ -408,15 +399,15 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, { @@ -408,15 +399,15 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
408 if (!this.navToolBar) 399 if (!this.navToolBar)
409 return; 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 if (ttNameField) 403 if (ttNameField)
413 ttNameField.setValue(this.crtContext.page.ttName); 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 if (ttNumberField) 407 if (ttNumberField)
417 ttNumberField.setValue(this.crtContext.page.ttIndex + 1); 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 if (ttTotalField) 411 if (ttTotalField)
421 ttTotalField.setValue(this.crtContext.page.ttNbIntervals); 412 ttTotalField.setValue(this.crtContext.page.ttNbIntervals);
422 }, 413 },
@@ -425,9 +416,8 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, { @@ -425,9 +416,8 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
425 loadMask.show(true); 416 loadMask.show(true);
426 417
427 var plotModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.plot.id); 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 loadMask.hide(); 421 loadMask.hide();
432 var t = e.getTransaction(); 422 var t = e.getTransaction();
433 if (e.status) 423 if (e.status)
@@ -456,28 +446,12 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, { @@ -456,28 +446,12 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
456 if (this.navToolBar) 446 if (this.navToolBar)
457 this.navToolBar.removeAll(true); 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 var commonItemsCfg = [ 449 var commonItemsCfg = [
470 '-', 450 '-',
471 { 451 {
472 xtype: 'tbspacer', 452 xtype: 'tbspacer',
473 width: 20 453 width: 20
474 }, 454 },
475 - this.multiPlotCheck,  
476 - {  
477 - xtype: 'tbspacer',  
478 - width: 2  
479 - },  
480 - '-',  
481 '->', 455 '->',
482 { 456 {
483 text: 'Get HST Data', 457 text: 'Get HST Data',
@@ -515,7 +489,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, { @@ -515,7 +489,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
515 } 489 }
516 else 490 else
517 --ttintervalIndex; 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,7 +508,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
534 else 508 else
535 ++ttintervalIndex; 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,17 +516,17 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
542 text: 'Go to Interval #', 516 text: 'Go to Interval #',
543 scope: this, 517 scope: this,
544 handler: function(bt){ 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 var goToIndex = ttGotoNumberField.getValue() - 1; 520 var goToIndex = ttGotoNumberField.getValue() - 1;
547 if ((goToIndex < 0) || (goToIndex >= this.crtContext.page.ttNbIntervals)) 521 if ((goToIndex < 0) || (goToIndex >= this.crtContext.page.ttNbIntervals))
548 myDesktopApp.errorMsg('This interval number is outside of the current timeTable'); 522 myDesktopApp.errorMsg('This interval number is outside of the current timeTable');
549 else 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 xtype: 'numberfield', 528 xtype: 'numberfield',
555 - id : 'tt-goto-number-'+this.tabId, 529 + id : 'tt-goto-number-'+this.interactiveId,
556 hideTrigger: true, 530 hideTrigger: true,
557 width: 50, 531 width: 50,
558 minValue: 1 532 minValue: 1
@@ -562,7 +536,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, { @@ -562,7 +536,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
562 ' ', 536 ' ',
563 { 537 {
564 xtype: 'textfield', 538 xtype: 'textfield',
565 - id: 'tt-table-'+this.tabId, 539 + id: 'tt-table-'+this.interactiveId,
566 labelAlign: 'right', 540 labelAlign: 'right',
567 labelWidth: 30, 541 labelWidth: 30,
568 fieldLabel: 'Table', 542 fieldLabel: 'Table',
@@ -571,7 +545,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, { @@ -571,7 +545,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
571 }, 545 },
572 { 546 {
573 xtype: 'textfield', 547 xtype: 'textfield',
574 - id: 'tt-number-'+this.tabId, 548 + id: 'tt-number-'+this.interactiveId,
575 labelAlign: 'right', 549 labelAlign: 'right',
576 labelWidth: 30, 550 labelWidth: 30,
577 fieldLabel: 'Int #', 551 fieldLabel: 'Int #',
@@ -580,7 +554,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, { @@ -580,7 +554,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
580 }, 554 },
581 { 555 {
582 xtype: 'textfield', 556 xtype: 'textfield',
583 - id: 'tt-total-'+this.tabId, 557 + id: 'tt-total-'+this.interactiveId,
584 labelAlign: 'right', 558 labelAlign: 'right',
585 labelWidth: 30, 559 labelWidth: 30,
586 fieldLabel: 'Total', 560 fieldLabel: 'Total',
@@ -595,7 +569,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, { @@ -595,7 +569,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
595 text: 'Backward', 569 text: 'Backward',
596 scope: this, 570 scope: this,
597 handler: function(){ 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,7 +577,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
603 text: '1/2 Backward', 577 text: '1/2 Backward',
604 scope: this, 578 scope: this,
605 handler: function(){ 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,7 +585,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
611 text: '1/2 Forward', 585 text: '1/2 Forward',
612 scope: this, 586 scope: this,
613 handler: function(){ 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,7 +593,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
619 text: 'Forward', 593 text: 'Forward',
620 scope: this, 594 scope: this,
621 handler: function(){ 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,7 +623,7 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
649 623
650 init: function(configResult){ 624 init: function(configResult){
651 this.crtContext = configResult.context; 625 this.crtContext = configResult.context;
652 - this.tabId = configResult.tabId; 626 + this.interactiveId = configResult.interactiveId;
653 627
654 this.coordinatesField = new Ext.toolbar.TextItem({ 628 this.coordinatesField = new Ext.toolbar.TextItem({
655 width: 300, 629 width: 300,
@@ -700,13 +674,6 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, { @@ -700,13 +674,6 @@ Ext.define(&#39;amdaUI.PlotTabResultUI&#39;, {
700 674
701 this.updateTimeTableInfo(); 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 var plotResultTabPanelConfig = { 677 var plotResultTabPanelConfig = {
711 preventHeader : true, 678 preventHeader : true,
712 autoScroll: true, 679 autoScroll: true,
js/app/views/PlotUI.js
@@ -10,454 +10,210 @@ @@ -10,454 +10,210 @@
10 10
11 11
12 Ext.define('amdaUI.PlotUI', { 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 * plot method called by 'Do Plot' button to launch the plot process 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,6 +61,20 @@ Ext.define(&#39;amdaUI.TimeSelectorUI&#39;, {
61 getActiveTimeSource: function() { 61 getActiveTimeSource: function() {
62 return this.timeSrc.getActiveTab().getItemId(); 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 initComponent: function() { 79 initComponent: function() {
66 this.activeField = null; 80 this.activeField = null;
js/resources/css/AccueilAmda.css
@@ -192,7 +192,6 @@ body{ @@ -192,7 +192,6 @@ body{
192 font-family: orbitronbold; 192 font-family: orbitronbold;
193 font-size: 16px; 193 font-size: 16px;
194 color: rgba(0, 107, 179, 0.7); 194 color: rgba(0, 107, 179, 0.7);
195 - font-weight: bold;  
196 } 195 }
197 #userLogin { 196 #userLogin {
198 position: relative; 197 position: relative;
@@ -217,7 +216,6 @@ body{ @@ -217,7 +216,6 @@ body{
217 font-family: orbitronbold; 216 font-family: orbitronbold;
218 font-size: 16px; 217 font-size: 16px;
219 color: rgba(0, 107, 179, 0.9); 218 color: rgba(0, 107, 179, 0.9);
220 - font-weight: bold;  
221 } 219 }
222 /* โ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ข ANNOUCEMENTSโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ข*/ 220 /* โ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ข ANNOUCEMENTSโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ข*/
223 #textAbout { 221 #textAbout {
js/resources/css/amda.css
@@ -462,10 +462,6 @@ p + p { @@ -462,10 +462,6 @@ p + p {
462 background-image:url( ../images/16x16/plot_page.png ) !important; 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 .icon-plot-layout { 465 .icon-plot-layout {
470 background-image:url( ../images/16x16/plot_layout.png ) !important; 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,7 +151,6 @@ class AmdaAction
151 $isParameter = false; 151 $isParameter = false;
152 $isAddable = false; 152 $isAddable = false;
153 $isSimulation = false; 153 $isSimulation = false;
154 - $plotTabs = FALSE;  
155 $rank = null; 154 $rank = null;
156 $skip = FALSE; 155 $skip = FALSE;
157 156
@@ -185,19 +184,6 @@ class AmdaAction @@ -185,19 +184,6 @@ class AmdaAction
185 else { 184 else {
186 $info = $id; 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 break; 187 break;
202 188
203 // case 'alias': 189 // case 'alias':
@@ -597,7 +583,7 @@ class AmdaAction @@ -597,7 +583,7 @@ class AmdaAction
597 } 583 }
598 584
599 $childrenToReturn[] = array('text' => $name, 'id' => $id, 'nodeType' => $nodeType, 'info' => $info, 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 'component_info' => isset($component_info) ? $component_info : NULL, 587 'component_info' => isset($component_info) ? $component_info : NULL,
602 'iconCls' => isset($iconCls) ? $iconCls : NULL ); 588 'iconCls' => isset($iconCls) ? $iconCls : NULL );
603 } 589 }
@@ -826,7 +812,6 @@ class AmdaAction @@ -826,7 +812,6 @@ class AmdaAction
826 break; 812 break;
827 case 'condition' : 813 case 'condition' :
828 case 'request' : 814 case 'request' :
829 - case 'plottab' :  
830 $objectMgr = new RequestMgr($obj->nodeType); 815 $objectMgr = new RequestMgr($obj->nodeType);
831 break; 816 break;
832 case 'alias' : 817 case 'alias' :
@@ -916,7 +901,6 @@ class AmdaAction @@ -916,7 +901,6 @@ class AmdaAction
916 break; 901 break;
917 case 'condition' : 902 case 'condition' :
918 case 'request' : 903 case 'request' :
919 - case 'plottab' :  
920 $objectMgr = new RequestMgr($obj->nodeType); 904 $objectMgr = new RequestMgr($obj->nodeType);
921 break; 905 break;
922 default: 906 default:
@@ -1437,11 +1421,10 @@ class AmdaAction @@ -1437,11 +1421,10 @@ class AmdaAction
1437 return array('success' => true); 1421 return array('success' => true);
1438 } 1422 }
1439 1423
1440 - public function interactivePlot($obj, $multiPlotState) 1424 + public function interactivePlot($obj)
1441 { 1425 {
1442 $inputobj = (Object)array( 1426 $inputobj = (Object)array(
1443 'action' => $obj, 1427 'action' => $obj,
1444 - 'multiPlotState' => $multiPlotState  
1445 ); 1428 );
1446 return $this->executeRequest($inputobj, FunctionTypeEnumClass::ACTION); 1429 return $this->executeRequest($inputobj, FunctionTypeEnumClass::ACTION);
1447 } 1430 }
php/classes/RequestMgr.php
@@ -30,7 +30,7 @@ class RequestMgr extends AmdaObjectMgr @@ -30,7 +30,7 @@ class RequestMgr extends AmdaObjectMgr
30 $this->attributes = array('name' => ''); 30 $this->attributes = array('name' => '');
31 $this->optionalAttributes = array(); 31 $this->optionalAttributes = array();
32 32
33 - if ($type == 'request' || $type == 'plottab') 33 + if ($type == 'request' )
34 { 34 {
35 $this->id_prefix = 'req_'; 35 $this->id_prefix = 'req_';
36 } 36 }
@@ -73,47 +73,11 @@ class RequestMgr extends AmdaObjectMgr @@ -73,47 +73,11 @@ class RequestMgr extends AmdaObjectMgr
73 73
74 public function validNameObject($p) 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 return parent::validNameObject($p); 76 return parent::validNameObject($p);
83 } 77 }
84 78
85 public function renameObject($p) 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 return parent::renameObject($p); 81 return parent::renameObject($p);
118 } 82 }
119 83
@@ -225,17 +189,6 @@ class RequestMgr extends AmdaObjectMgr @@ -225,17 +189,6 @@ class RequestMgr extends AmdaObjectMgr
225 } 189 }
226 190
227 $additional = array(); 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 $this->descFileName = USERREQDIR.$this->id; 193 $this->descFileName = USERREQDIR.$this->id;
241 $p->id = $this->id; 194 $p->id = $this->id;
@@ -258,17 +211,12 @@ class RequestMgr extends AmdaObjectMgr @@ -258,17 +211,12 @@ class RequestMgr extends AmdaObjectMgr
258 switch ($obj->nodeType) 211 switch ($obj->nodeType)
259 { 212 {
260 case 'request' : 213 case 'request' :
261 - foreach ($obj->tabs as $tab)  
262 - {  
263 - $timesrc = $tab->{'multi-plot-linked'} ? $obj->timesrc : $tab->timesrc;  
264 - 214 +
265 //TODO check TT as well (first start and last stop ?) 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 $argsTab = array(); 218 $argsTab = array();
271 - foreach ($tab->panels as $panel) 219 + foreach ($obj->panels as $panel)
272 { 220 {
273 $params = array(); 221 $params = array();
274 foreach ($panel->params as $param) 222 foreach ($panel->params as $param)
@@ -283,12 +231,11 @@ class RequestMgr extends AmdaObjectMgr @@ -283,12 +231,11 @@ class RequestMgr extends AmdaObjectMgr
283 if (count($params) > 0) 231 if (count($params) > 0)
284 { 232 {
285 $argsTab['param'] = array_unique($params); 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 if (count($argsTab) > 0) $args[] = $argsTab; 238 if (count($argsTab) > 0) $args[] = $argsTab;
291 - }  
292 break; 239 break;
293 case 'condition' : 240 case 'condition' :
294 //$argsTab = array(); 241 //$argsTab = array();
php/classes/UserMgr.php
@@ -517,6 +517,13 @@ class UserMgr @@ -517,6 +517,13 @@ class UserMgr
517 $this->isFirst = true; 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 if (file_exists($this->userdir.'newLogin')) { 527 if (file_exists($this->userdir.'newLogin')) {
521 touch($this->userdir.'lastLogin', filemtime($this->userdir.'newLogin')); 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 \ No newline at end of file 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,7 +183,7 @@ $API = array(
183 //AKKA - New action to clean user WS 183 //AKKA - New action to clean user WS
184 'cleanUserWS'=>array('len'=>0), 184 'cleanUserWS'=>array('len'=>0),
185 'deleteSpecialInfo'=>array('len'=>1), 185 'deleteSpecialInfo'=>array('len'=>1),
186 - 'interactivePlot'=>array('len'=>2), 186 + 'interactivePlot'=>array('len'=>1),
187 'getParamPlotInit'=>array('len'=>1), 187 'getParamPlotInit'=>array('len'=>1),
188 'getParamInfo'=>array('len'=>1), 188 'getParamInfo'=>array('len'=>1),
189 'getDerivedParamInfo'=>array('len'=>1), 189 'getDerivedParamInfo'=>array('len'=>1),
php/downloadPlot.php
@@ -10,19 +10,19 @@ if (!isset($_POST[&#39;sessionId&#39;])) @@ -10,19 +10,19 @@ if (!isset($_POST[&#39;sessionId&#39;]))
10 } 10 }
11 $sessionId = $_POST['sessionId']; 11 $sessionId = $_POST['sessionId'];
12 12
13 -if (!isset($_POST['tabId'])) 13 +if (!isset($_POST['interactiveId']))
14 { 14 {
15 header("HTTP/1.0 400 Bad Request"); 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 exit; 17 exit;
18 } 18 }
19 -$tabId = $_POST['tabId']; 19 +$interactiveId = $_POST['interactiveId'];
20 20
21 $preview = empty($_POST['preview']) ? FALSE : $_POST['preview']; 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 // Must be fresh start 27 // Must be fresh start
28 if( headers_sent() ) 28 if( headers_sent() )
@@ -38,10 +38,10 @@ function download_plot($sessionId, $tabId, $preview) @@ -38,10 +38,10 @@ function download_plot($sessionId, $tabId, $preview)
38 38
39 //Build file path 39 //Build file path
40 if (!$preview) { 40 if (!$preview) {
41 - $fullPath = USERPATH."/".$sessionId."/RES/Plot_/".$tabId.".png"; 41 + $fullPath = USERPATH."/".$sessionId."/RES/Plot_/".$interactiveId.".png";
42 } 42 }
43 else { 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 // File Exists? 46 // File Exists?
47 if( file_exists($fullPath) ){ 47 if( file_exists($fullPath) ){
php/src/cdfsamplingfromdata.c
@@ -126,7 +126,7 @@ int main(int argc, char *argv[]) @@ -126,7 +126,7 @@ int main(int argc, char *argv[])
126 if (datatype == CDF_TIME_TT2000) { 126 if (datatype == CDF_TIME_TT2000) {
127 dbl_value_ = CDF_TT2000_to_UTC_EPOCH(int_value[0]); 127 dbl_value_ = CDF_TT2000_to_UTC_EPOCH(int_value[0]);
128 dbl_value = CDF_TT2000_to_UTC_EPOCH(int_value[1]); 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 else { 131 else {
132 if (datatype == CDF_EPOCH16) { 132 if (datatype == CDF_EPOCH16) {
@@ -139,7 +139,7 @@ int main(int argc, char *argv[]) @@ -139,7 +139,7 @@ int main(int argc, char *argv[])
139 EPOCH16breakdown(epoch16, &year, &month, &day, &hour, &minute, &sec, &msec, &mksec, &nsec, &psec); 139 EPOCH16breakdown(epoch16, &year, &month, &day, &hour, &minute, &sec, &msec, &mksec, &nsec, &psec);
140 value[1] = computeEPOCH(year, month, day, hour, minute, sec, msec); 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 // fprintf(stdout,"value %f\n", value[11]-value[10]); 145 // fprintf(stdout,"value %f\n", value[11]-value[10]);
@@ -150,5 +150,5 @@ int main(int argc, char *argv[]) @@ -150,5 +150,5 @@ int main(int argc, char *argv[])
150 if ((cstatus = CDFlib(CLOSE_, CDF_, NULL_)) != CDF_OK) 150 if ((cstatus = CDFlib(CLOSE_, CDF_, NULL_)) != CDF_OK)
151 cdf_handle_error (cstatus); 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,7 +162,7 @@ int main(int argc, char *argv[])
162 if (datatype == CDF_TIME_TT2000) { 162 if (datatype == CDF_TIME_TT2000) {
163 dbl_value_ = CDF_TT2000_to_UTC_EPOCH(int_value[i-1]); 163 dbl_value_ = CDF_TT2000_to_UTC_EPOCH(int_value[i-1]);
164 dbl_value = CDF_TT2000_to_UTC_EPOCH(int_value[i]); 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 else { 167 else {
168 if (datatype == CDF_EPOCH16) { 168 if (datatype == CDF_EPOCH16) {
@@ -175,7 +175,7 @@ int main(int argc, char *argv[]) @@ -175,7 +175,7 @@ int main(int argc, char *argv[])
175 EPOCH16breakdown(epoch16, &year, &month, &day, &hour, &minute, &sec, &msec, &mksec, &nsec, &psec); 175 EPOCH16breakdown(epoch16, &year, &month, &day, &hour, &minute, &sec, &msec, &mksec, &nsec, &psec);
176 value[i] = computeEPOCH(year, month, day, hour, minute, sec, msec); 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 // fprintf(stdout,"value %f\n", value[11]-value[10]); 181 // fprintf(stdout,"value %f\n", value[11]-value[10]);
@@ -194,5 +194,5 @@ int main(int argc, char *argv[]) @@ -194,5 +194,5 @@ int main(int argc, char *argv[])
194 cdf_handle_error (cstatus); 194 cdf_handle_error (cstatus);
195 195
196 // fprintf(stdout,"%d %f\n",min[1], (float)min[0]/100.0); 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 }