Commit 25cb4f8de732ca0ad1613c21a026e140a561fe64
Exists in
master
and in
94 other branches
Merge branch 'master' of https://gitlab.irap.omp.eu/CDPP/AMDA_IHM
Showing
38 changed files
with
3730 additions
and
2839 deletions
Show diff stats
help/plotHOWTO
1 | 1 | <li>1. To plot a parameter <i>drag</i> it from the Parameters tree and <i>drop</i> onto the panel |
2 | -<li>2. <i>Link to MultiPlot</i> replaces the individual plot tab TimeSelector with the common for all plot tabs "MultiTime" Selector | |
3 | -<li>3. Check <i>Extended Plot Options</i> to get control over all available plot options | |
2 | +<li>2. Check <i>Extended Plot Options</i> to get control over all available plot options | |
3 | + | |
4 | 4 | |
5 | - | |
6 | 5 | \ No newline at end of file |
... | ... |
js/app/controllers/InteractiveModule.js
... | ... | @@ -37,12 +37,15 @@ Ext.define('amdaDesktop.InteractiveModule', { |
37 | 37 | /** |
38 | 38 | * Window Creation method of the Module |
39 | 39 | */ |
40 | - createWindow : function (onShowEvent) { | |
40 | + createWindow : function (onShowEvent, onAfterCreateObject) { | |
41 | 41 | |
42 | 42 | if (this.linkedNode === null){ |
43 | 43 | this.createLinkedNode(); |
44 | 44 | } |
45 | - this.createObject(); | |
45 | + this.createObject(); | |
46 | + if (onAfterCreateObject) { | |
47 | + onAfterCreateObject(); | |
48 | + } | |
46 | 49 | var desktop = this.app.getDesktop(); |
47 | 50 | var win = desktop.getWindow(this.id); |
48 | 51 | var me = this; |
... | ... |
js/app/controllers/PlotModule.js
... | ... | @@ -13,8 +13,8 @@ Ext.define('amdaDesktop.PlotModule', { |
13 | 13 | |
14 | 14 | requires: [ |
15 | 15 | 'amdaUI.PlotUI', |
16 | - 'amdaPlotObj.PlotRequestObject', | |
17 | - 'amdaModel.PlotNode', | |
16 | + 'amdaPlotObj.MultiplotRequestObject', | |
17 | + 'amdaModel.MultiplotNode', | |
18 | 18 | 'amdaUI.PlotTabResultUI', |
19 | 19 | 'amdaPlotComp.PlotPreviewUI' |
20 | 20 | ], |
... | ... | @@ -26,7 +26,7 @@ Ext.define('amdaDesktop.PlotModule', { |
26 | 26 | * @cfg {String} data models |
27 | 27 | * @required |
28 | 28 | */ |
29 | - nodeDataModel : 'amdaModel.PlotNode', | |
29 | + nodeDataModel : 'amdaModel.MultiplotNode', | |
30 | 30 | |
31 | 31 | /** |
32 | 32 | * @cfg {String} window definitions |
... | ... | @@ -40,173 +40,197 @@ Ext.define('amdaDesktop.PlotModule', { |
40 | 40 | |
41 | 41 | plotResultWindowsManager : new Ext.AbstractManager(), |
42 | 42 | |
43 | - computeResultWindowSize : function(panelResult) | |
44 | - { | |
45 | - var size = panelResult.getImageSize(); | |
46 | - size.width += 30; | |
47 | - size.height += 95; | |
48 | - | |
49 | - return size; | |
50 | - }, | |
43 | + computeResultWindowSize : function(panelResult) { | |
44 | + var size = panelResult.getImageSize(); | |
45 | + size.width += 30; | |
46 | + size.height += 95; | |
47 | + return size; | |
48 | + }, | |
51 | 49 | |
52 | - computePreviewWindowSize : function(previewContent) | |
53 | - { | |
54 | - var size = previewContent.getImageSize(); | |
55 | - size.width += 30; | |
56 | - size.height += 65; | |
57 | - | |
58 | - return size; | |
59 | - }, | |
50 | + computePreviewWindowSize : function(previewContent) { | |
51 | + var size = previewContent.getImageSize(); | |
52 | + size.width += 30; | |
53 | + size.height += 65; | |
54 | + return size; | |
55 | + }, | |
60 | 56 | |
61 | 57 | updateInteractiveSession : function(session, newplot) { |
62 | - var me = this; | |
63 | - | |
64 | - | |
65 | - | |
66 | - Ext.each(session.result, function (tabResult, index) { | |
67 | - if (logExecTime && tabResult.exectime) | |
68 | - { | |
69 | - console.log("CMD EXEC TIME FOR "+tabResult.plot+" = "+tabResult.exectime+"ms"); | |
70 | - } | |
58 | + var me = this; | |
71 | 59 | |
72 | - if (tabResult.preview) | |
73 | - { | |
74 | - var plotPreviewConfig = { | |
75 | - folder : session.folder, | |
76 | - plotFile : tabResult.plot, | |
77 | - context : tabResult.context, | |
78 | - tabId : tabResult.id | |
79 | - }; | |
80 | - me.updatePreview(plotPreviewConfig); | |
81 | - return; | |
82 | - } | |
83 | - | |
84 | - var winResultId = tabResult.id+"-win"; | |
85 | - | |
86 | - var winResult = me.getWindowResult(winResultId); | |
87 | - | |
88 | - var plotTabConfig = { | |
89 | - folder : session.folder, | |
90 | - plotFile : tabResult.plot, | |
91 | - context : tabResult.context, | |
92 | - tabId : tabResult.id, | |
93 | - multiplot : tabResult.multiplot, | |
94 | - isInterval: tabResult.isInterval, | |
95 | - ttName : tabResult.ttName, | |
96 | - ttIndex : tabResult.ttIndex, | |
97 | - ttNbIntervals : tabResult.ttNbIntervals, | |
98 | - ttFileIndex : tabResult.ttFileIndex | |
99 | - }; | |
60 | + | |
61 | + Ext.each(session.result, function (tabResult, index) { | |
62 | + if (logExecTime && tabResult.exectime) { | |
63 | + console.log("CMD EXEC TIME FOR "+tabResult.plot+" = "+tabResult.exectime+"ms"); | |
64 | + } | |
65 | + | |
66 | + if (tabResult.preview) { | |
67 | + var plotPreviewConfig = { | |
68 | + folder : session.folder, | |
69 | + plotFile : tabResult.plot, | |
70 | + context : tabResult.context, | |
71 | + interactiveId : tabResult.id | |
72 | + }; | |
73 | + me.updatePreview(plotPreviewConfig); | |
74 | + return; | |
75 | + } | |
76 | + | |
77 | + var winResultId = tabResult.id+"-win"; | |
100 | 78 | |
101 | - if (winResult == null) { | |
102 | - | |
103 | - var x = 50 + tabResult.index * 50; | |
104 | - var y = 100 + tabResult.index * 20; | |
105 | - | |
106 | - //create new result win | |
107 | - var panelResult = new amdaUI.PlotTabResultUI(plotTabConfig); | |
79 | + var winResult = me.getWindowResult(winResultId); | |
108 | 80 | |
109 | - var size = me.computeResultWindowSize(panelResult); | |
81 | + var plotTabConfig = { | |
82 | + folder : session.folder, | |
83 | + plotFile : tabResult.plot, | |
84 | + context : tabResult.context, | |
85 | + interactiveId : tabResult.id, | |
86 | + isInterval: tabResult.isInterval, | |
87 | + ttName : tabResult.ttName, | |
88 | + ttIndex : tabResult.ttIndex, | |
89 | + ttNbIntervals : tabResult.ttNbIntervals, | |
90 | + ttFileIndex : tabResult.ttFileIndex | |
91 | + }; | |
110 | 92 | |
111 | - var win = myDesktopApp.getDesktop().createWindow({ | |
112 | - id : tabResult.id+"-win", | |
113 | - title : 'Plot '+(tabResult.index+1), | |
114 | - width : size.width, | |
115 | - height: size.height, | |
116 | - x : x, | |
117 | - y : y, | |
118 | - layout: 'fit', | |
119 | - items : [ | |
120 | - panelResult | |
121 | - ], | |
122 | - listeners: { | |
123 | - scope: me, | |
124 | - beforeclose: function(win,opt) { | |
125 | - me.plotResultWindowsManager.unregister(win); | |
126 | - } | |
127 | - }, | |
128 | - getPanelResult: function() { | |
129 | - return panelResult; | |
130 | - } | |
131 | - }); | |
132 | - win.show(); | |
133 | - me.plotResultWindowsManager.register(win); | |
134 | - } | |
135 | - else | |
136 | - { | |
137 | - //update result | |
138 | - winResult.getPanelResult().updatePlotImage(plotTabConfig, newplot); | |
139 | - //update window size | |
140 | - var size = me.computeResultWindowSize(winResult.getPanelResult()); | |
141 | - winResult.setSize(size.width, size.height); | |
142 | - | |
143 | - winResult.toFront(); | |
144 | - } | |
145 | - }); | |
93 | + if (winResult == null) { | |
94 | + var x = 50 + tabResult.index * 50; | |
95 | + var y = 100 + tabResult.index * 20; | |
96 | + //create new result win | |
97 | + var panelResult = new amdaUI.PlotTabResultUI(plotTabConfig); | |
98 | + | |
99 | + var size = me.computeResultWindowSize(panelResult); | |
100 | + | |
101 | + var win = myDesktopApp.getDesktop().createWindow({ | |
102 | + id : tabResult.id+"-win", | |
103 | + title : tabResult.title, | |
104 | + width : size.width, | |
105 | + height: size.height, | |
106 | + x : x, | |
107 | + y : y, | |
108 | + layout: 'fit', | |
109 | + items : [ | |
110 | + panelResult | |
111 | + ], | |
112 | + listeners: { | |
113 | + scope: me, | |
114 | + beforeclose: function(win,opt) { | |
115 | + me.plotResultWindowsManager.unregister(win); | |
116 | + } | |
117 | + }, | |
118 | + getPanelResult: function() { | |
119 | + return panelResult; | |
120 | + } | |
121 | + }); | |
122 | + win.show(); | |
123 | + me.plotResultWindowsManager.register(win); | |
124 | + } | |
125 | + else { | |
126 | + //update result | |
127 | + winResult.getPanelResult().updatePlotImage(plotTabConfig, newplot); | |
128 | + //update window size | |
129 | + var size = me.computeResultWindowSize(winResult.getPanelResult()); | |
130 | + winResult.setTitle(tabResult.title); | |
131 | + winResult.setSize(size.width, size.height); | |
132 | + winResult.toFront(); | |
133 | + } | |
134 | + }); | |
146 | 135 | }, |
147 | 136 | |
148 | 137 | closeInteractiveSession : function() { |
149 | - var me = this; | |
150 | - this.plotResultWindowsManager.each(function (key, value, length) { | |
151 | - value.close(); | |
152 | - }); | |
138 | + var me = this; | |
139 | + this.plotResultWindowsManager.each(function (key, value, length) { | |
140 | + value.close(); | |
141 | + }); | |
153 | 142 | }, |
154 | - | |
143 | + | |
155 | 144 | updatePreview : function(plotPreviewConfig) { |
156 | - var winPreviewId = "plot-preview-win"; | |
157 | - | |
158 | - var winPreview = this.getWindowResult(winPreviewId); | |
159 | - | |
160 | - if (winPreview == null) { | |
161 | - //create new preview win | |
162 | - var previewContent = new amdaPlotComp.PlotPreviewUI(plotPreviewConfig); | |
163 | - | |
164 | - var size = this.computePreviewWindowSize(previewContent); | |
165 | - | |
166 | - var win = myDesktopApp.getDesktop().createWindow({ | |
167 | - id : winPreviewId, | |
168 | - title : 'Plot Preview', | |
169 | - width : size.width, | |
170 | - height: size.height, | |
171 | - layout: 'fit', | |
172 | - items : [ | |
173 | - previewContent | |
174 | - ], | |
175 | - listeners: { | |
176 | - scope: this, | |
177 | - beforeclose: function(win,opt) { | |
178 | - this.plotResultWindowsManager.unregister(win); | |
179 | - } | |
180 | - }, | |
181 | - getPreviewContent: function() { | |
182 | - return previewContent; | |
183 | - } | |
184 | - }); | |
185 | - win.show(); | |
186 | - this.plotResultWindowsManager.register(win); | |
187 | - } | |
188 | - else | |
189 | - { | |
190 | - //update result | |
191 | - winPreview.getPreviewContent().updatePlotImage(plotPreviewConfig); | |
192 | - //update window size | |
193 | - var size = this.computePreviewWindowSize(winPreview.getPreviewContent()); | |
194 | - winPreview.setSize(size.width, size.height); | |
195 | - winPreview.toFront(); | |
196 | - } | |
197 | - }, | |
198 | - | |
199 | - getInteractiveMultiPlotState : function() { | |
200 | - var state = {}; | |
201 | - this.plotResultWindowsManager.each(function (key, value, length) { | |
202 | - if (value.getPanelResult) | |
203 | - state[value.getPanelResult().tabId] = value.getPanelResult().getInteractiveMultiPlotState(); | |
204 | - }); | |
205 | - return state; | |
145 | + var winPreviewId = "plot-preview-win"; | |
146 | + | |
147 | + var winPreview = this.getWindowResult(winPreviewId); | |
148 | + | |
149 | + if (winPreview == null) { | |
150 | + //create new preview win | |
151 | + var previewContent = new amdaPlotComp.PlotPreviewUI(plotPreviewConfig); | |
152 | + | |
153 | + var size = this.computePreviewWindowSize(previewContent); | |
154 | + | |
155 | + var win = myDesktopApp.getDesktop().createWindow({ | |
156 | + id : winPreviewId, | |
157 | + title : 'Plot Preview', | |
158 | + width : size.width, | |
159 | + height: size.height, | |
160 | + layout: 'fit', | |
161 | + items : [ | |
162 | + previewContent | |
163 | + ], | |
164 | + listeners: { | |
165 | + scope: this, | |
166 | + beforeclose: function(win,opt) { | |
167 | + this.plotResultWindowsManager.unregister(win); | |
168 | + } | |
169 | + }, | |
170 | + getPreviewContent: function() { | |
171 | + return previewContent; | |
172 | + } | |
173 | + }); | |
174 | + win.show(); | |
175 | + this.plotResultWindowsManager.register(win); | |
176 | + } | |
177 | + else { | |
178 | + //update result | |
179 | + winPreview.getPreviewContent().updatePlotImage(plotPreviewConfig); | |
180 | + //update window size | |
181 | + var size = this.computePreviewWindowSize(winPreview.getPreviewContent()); | |
182 | + winPreview.setSize(size.width, size.height); | |
183 | + winPreview.toFront(); | |
184 | + } | |
206 | 185 | }, |
207 | 186 | |
208 | 187 | getWindowResult: function(winResultId){ |
209 | 188 | if (!this.plotResultWindowsManager.get(winResultId)) return null; |
210 | 189 | return this.plotResultWindowsManager.get(winResultId); |
190 | + }, | |
191 | + | |
192 | + addParameter : function(paramNode) { | |
193 | + var me = this; | |
194 | + var desktop = this.app.getDesktop(); | |
195 | + var win = desktop.getWindow(this.id); | |
196 | + if (win) { | |
197 | + me.getUiContent().addParameter(paramNode, false); | |
198 | + win.show(); | |
199 | + } | |
200 | + else { | |
201 | + this.createWindow(function () { | |
202 | + me.getUiContent().addParameter(paramNode, true); | |
203 | + }); | |
204 | + } | |
205 | + }, | |
206 | + | |
207 | + editPlot : function(plotNode) { | |
208 | + var me = this; | |
209 | + var desktop = this.app.getDesktop(); | |
210 | + var win = desktop.getWindow(this.id); | |
211 | + if (win) { | |
212 | + // Plot UI is opened => add plot in a new tab | |
213 | + me.getUiContent().editPlot(plotNode); | |
214 | + win.show(); | |
215 | + } | |
216 | + else { | |
217 | + // Plot UI is closed | |
218 | + this.createWindow(null, function() { | |
219 | + //This is the onAfterCreateObject callback | |
220 | + //Add plot node to the multiplot object | |
221 | + me.linkedNode.get('object').plots().removeAll(); | |
222 | + me.linkedNode.get('object').plots().add(plotNode); | |
223 | + }); | |
224 | + } | |
225 | + }, | |
226 | + | |
227 | + syncAfterRename: function(renamedNode) { | |
228 | + var me = this; | |
229 | + var desktop = this.app.getDesktop(); | |
230 | + var win = desktop.getWindow(this.id); | |
231 | + if (win) { | |
232 | + me.getUiContent().updateTabs(); | |
233 | + me.getUiContent().updateRequestName(renamedNode); | |
234 | + } | |
211 | 235 | } |
212 | 236 | }); |
... | ... |
js/app/models/AmdaNode.js
... | ... | @@ -128,20 +128,7 @@ Ext.define('amdaModel.AmdaNode', { |
128 | 128 | } |
129 | 129 | // if this node is a leaf and have no child |
130 | 130 | else if (this.isLeaf() || this.get('nodeType' ) == 'derivedParam' ) { |
131 | - if (this.get('nodeType') == 'plottab') { | |
132 | - itemKind = amdaUI.ExplorerUI.ITEM_KIND_PTAB; | |
133 | - } | |
134 | - else { | |
135 | - itemKind = amdaUI.ExplorerUI.ITEM_KIND_LEAF; | |
136 | - } | |
137 | - } | |
138 | - else if (this.get('nodeType') == 'request') { | |
139 | - if (this.get('tabs') && (this.get('tabs').length > 0)) { | |
140 | - itemKind = amdaUI.ExplorerUI.ITEM_KIND_LEAF; | |
141 | - } | |
142 | - else { | |
143 | - itemKind = amdaUI.ExplorerUI.ITEM_KIND_DIRE; | |
144 | - } | |
131 | + itemKind = amdaUI.ExplorerUI.ITEM_KIND_LEAF; | |
145 | 132 | } |
146 | 133 | else if (this.get('isParameter') && this.get('nodeType' ) != 'derivedParam' ) { |
147 | 134 | itemKind = amdaUI.ExplorerUI.ITEM_KIND_PARA; |
... | ... |
js/app/models/AmdaTimeObject.js
... | ... | @@ -7,11 +7,7 @@ |
7 | 7 | * |
8 | 8 | * @author elena |
9 | 9 | * @version $Id: AmdaTimeObject.js 1534 2013-05-24 13:30:26Z myriam $ |
10 | - * @todo Validations | |
11 | - ****************************************************************************** | |
12 | - * FT Id : Date : Name - Description | |
13 | - ****************************************************************************** | |
14 | - * : :07/07/2011: elena โ creation | |
10 | + * @todo Validations | |
15 | 11 | */ |
16 | 12 | |
17 | 13 | |
... | ... | @@ -26,66 +22,70 @@ Ext.define('amdaModel.TTobject', { |
26 | 22 | } |
27 | 23 | }); |
28 | 24 | |
29 | - | |
30 | 25 | Ext.define('amdaModel.AmdaTimeObject', { |
31 | 26 | extend: 'amdaModel.AmdaObject', |
32 | 27 | statics:{ |
33 | 28 | inputTimeSrc: ['TimeTable','Interval','Catalog'] |
34 | - }, | |
29 | + }, | |
35 | 30 | fields : [ |
36 | - { name: 'resultId', type: 'string'}, | |
37 | - { name: 'folderId', type: 'string'}, | |
38 | - { name: 'processId', type: 'string'}, | |
39 | - { name: 'timesrc', type: 'string'/*, defaultValue: amdaModel.AmdaTimeObject.inputTimeSrc[1] /*'Interval'*/ }, | |
40 | - { name: 'startDate', type: 'date', defaultValue:Ext.Date.add(Ext.Date.clearTime(new Date()),Ext.Date.DAY,-1), | |
41 | - convert: function(value,rec) { | |
42 | - if (!Ext.isDate(value)) { | |
43 | - var valueString = new String(value); | |
44 | - var date = new Date(valueString.replace(/\-/g,'\/').replace(/[T|Z]/g,' ')); | |
45 | - return date; | |
46 | - } | |
47 | - return value; | |
48 | - } | |
49 | - }, | |
50 | - { name: 'stopDate', type: 'date', defaultValue: Ext.Date.clearTime (new Date()), persist: false, | |
51 | - convert: function(value,rec) { | |
52 | - if (!Ext.isDate(value)){ | |
53 | - var valueString = new String(value); | |
54 | - var date = new Date(valueString.replace(/\-/g,'\/').replace(/[T|Z]/g,' ')); | |
55 | - return date; | |
56 | - } | |
57 | - return value; | |
58 | - } | |
59 | - | |
60 | - }, | |
61 | - { | |
62 | - name: 'durationDay', type: 'int', | |
63 | - convert: function(value, rec) { | |
64 | - return Ext.String.leftPad(Math.floor((rec.get('stopDate') - rec.get('startDate'))/86400000),4,'0'); | |
65 | - } | |
66 | - }, | |
67 | - { | |
68 | - name: 'durationHour', type: 'int', | |
69 | - convert: function(value, rec) { | |
70 | - var diffH = (rec.get('stopDate') - rec.get('startDate'))/3600000 % 24; | |
71 | - return Ext.String.leftPad(Math.floor(diffH), 2, '0'); | |
72 | - } | |
73 | - }, | |
74 | - { | |
75 | - name: 'durationMin', type: 'int', | |
76 | - convert: function(value, rec) { | |
77 | - var diffM = (rec.get('stopDate') - rec.get('startDate'))/60000 % 60; | |
78 | - return Ext.String.leftPad(Math.floor(diffM), 2, '0'); | |
79 | - } | |
80 | - }, | |
81 | - { | |
82 | - name: 'durationSec', type: 'int', | |
83 | - convert: function(value, rec) { | |
84 | - var diffS = (rec.get('stopDate') - rec.get('startDate'))/1000 % 60; | |
85 | - return Ext.String.leftPad(Math.floor(diffS), 2, '0'); | |
86 | - } | |
87 | - }, | |
88 | - { name: 'timeTables', defaultValue: null } // array of TTobject | |
89 | - ] | |
90 | - | |
31 | + { name: 'resultId', type: 'string'}, | |
32 | + { name: 'folderId', type: 'string'}, | |
33 | + { name: 'processId', type: 'string'}, | |
34 | + { name: 'timesrc', type: 'string'/*, defaultValue: amdaModel.AmdaTimeObject.inputTimeSrc[1] /*'Interval'*/ }, | |
35 | + { name: 'startDate', type: 'date', defaultValue:Ext.Date.add(Ext.Date.clearTime(new Date()),Ext.Date.DAY,-1), | |
36 | + convert: function(value,rec) { | |
37 | + if (!Ext.isDate(value)) { | |
38 | + var valueString = new String(value); | |
39 | + var date = new Date(valueString.replace(/\-/g,'\/').replace(/[T|Z]/g,' ')); | |
40 | + return date; | |
41 | + } | |
42 | + return value; | |
43 | + } | |
44 | + }, | |
45 | + { | |
46 | + name: 'stopDate', type: 'date', defaultValue: Ext.Date.clearTime (new Date()), persist: false, | |
47 | + convert: function(value,rec) { | |
48 | + if (!Ext.isDate(value)){ | |
49 | + var valueString = new String(value); | |
50 | + var date = new Date(valueString.replace(/\-/g,'\/').replace(/[T|Z]/g,' ')); | |
51 | + return date; | |
52 | + } | |
53 | + return value; | |
54 | + } | |
55 | + }, | |
56 | + { | |
57 | + name: 'durationDay', type: 'int', | |
58 | + convert: function(value, rec) { | |
59 | + var zoneOffset = rec.get('stopDate').getTimezoneOffset() - rec.get('startDate').getTimezoneOffset(); | |
60 | + | |
61 | + return Ext.String.leftPad(Math.floor((rec.get('stopDate') - rec.get('startDate') - zoneOffset*60000)/86400000),4,'0'); | |
62 | + } | |
63 | + }, | |
64 | + { | |
65 | + name: 'durationHour', type: 'int', | |
66 | + convert: function(value, rec) { | |
67 | + var zoneOffset = rec.get('stopDate').getTimezoneOffset() - rec.get('startDate').getTimezoneOffset(); | |
68 | + var diffH = (rec.get('stopDate') - rec.get('startDate') - zoneOffset*60000)/3600000 % 24; | |
69 | + | |
70 | + return Ext.String.leftPad(Math.floor(diffH), 2, '0'); | |
71 | + } | |
72 | + }, | |
73 | + { | |
74 | + name: 'durationMin', type: 'int', | |
75 | + convert: function(value, rec) { | |
76 | + var diffM = (rec.get('stopDate') - rec.get('startDate'))/60000 % 60; | |
77 | + | |
78 | + return Ext.String.leftPad(Math.floor(diffM), 2, '0'); | |
79 | + } | |
80 | + }, | |
81 | + { | |
82 | + name: 'durationSec', type: 'int', | |
83 | + convert: function(value, rec) { | |
84 | + var diffS = (rec.get('stopDate') - rec.get('startDate'))/1000 % 60; | |
85 | + | |
86 | + return Ext.String.leftPad(Math.floor(diffS), 2, '0'); | |
87 | + } | |
88 | + }, | |
89 | + { name: 'timeTables', defaultValue: null } // array of TTobject | |
90 | + ] | |
91 | 91 | }); |
... | ... |
js/app/models/BkgJobNode.js
js/app/models/DownloadNode.js
... | ... | @@ -62,90 +62,74 @@ Ext.define('amdaModel.DownloadNode', { |
62 | 62 | }); |
63 | 63 | }, |
64 | 64 | |
65 | - decodeObject: function(obj) { | |
66 | - var myValues = new Object(); | |
67 | - myValues.list=[]; | |
68 | - | |
69 | - if (!obj) { | |
70 | - var fullObject = this.get('realLinkedNode').get('object'); | |
71 | - } | |
72 | - else { | |
73 | - var fullObject = obj; | |
74 | - } | |
75 | - | |
76 | - var i = 0; | |
77 | - fullObject.tabs().each(function (tab) { | |
78 | - // only active tab | |
79 | - if (tab.get('id') == fullObject.get('last-plotted-tab')) | |
80 | - { | |
81 | - tab.panels().each(function (panel) { | |
82 | - panel.params().each(function (param) { | |
83 | - var myParam = new Object(); | |
84 | - myParam.paramid = param.get('paramid'); | |
85 | - myParam.type = param.get('type'); | |
86 | - myParam['dim1-index'] = param.get('dim1-index'); | |
87 | - myParam['dim1-sum-type'] = param.get('dim1-sum-type'); | |
88 | - myParam['dim1-min-value'] = param.get('dim1-min-value'); | |
89 | - myParam['dim1-max-value'] = param.get('dim1-max-value'); | |
90 | - myParam['dim1-min-index'] = param.get('dim1-min-index'); | |
91 | - myParam['dim1-max-index'] = param.get('dim1-max-index'); | |
92 | - myParam['dim2-index'] = param.get('dim2-index'); | |
93 | - myParam['dim2-sum-type'] = param.get('dim2-sum-type'); | |
94 | - myParam['dim2-min-value'] = param.get('dim2-min-value'); | |
95 | - myParam['dim2-max-value'] = param.get('dim2-max-value'); | |
96 | - myParam['dim2-min-index'] = param.get('dim2-min-index'); | |
97 | - myParam['dim2-max-index'] = param.get('dim2-max-index'); | |
98 | - myParam.template_args = param.get('template_args'); | |
99 | - if (!param.get('plotonly')) { | |
100 | - myValues.list[i] = myParam; | |
101 | - ++i; | |
102 | - } | |
103 | - else | |
104 | - alert('Parameter '+ myParam.paramid + ' is PlotOnly'); | |
105 | - }); | |
106 | - }); | |
107 | - if (tab.get('multi-plot-linked')) | |
108 | - { | |
109 | - var object = fullObject.data; | |
110 | - } | |
111 | - else | |
112 | - { | |
113 | - var object = tab.data; | |
114 | - } | |
115 | - myValues.timesrc = object.timesrc; | |
116 | - // if there's at least one timeTable name into 'timeTables' collection | |
117 | - if (myValues.timesrc == amdaModel.AmdaTimeObject.inputTimeSrc[0] | |
118 | - && object.timeTables | |
119 | - && object.timeTables.length ){ | |
120 | - // get complete timeTables collection | |
121 | - var timeTables = object.timeTables; | |
122 | - // init an empty array for timeTables | |
123 | - myValues.timeTables=[]; | |
124 | - // for each interval record | |
125 | - Ext.Array.each(timeTables, function(item, index, all){ | |
126 | - if (!item.$className) { | |
127 | - myValues.timeTables[index] = {timeTableName : item.timeTableName, id : item.id}; | |
128 | - } | |
129 | - // get Json simplified value | |
130 | - else { | |
131 | - myValues.timeTables[index] = item.getJsonValues(); | |
132 | - } | |
133 | - }); | |
134 | - } | |
135 | - else { | |
136 | - myValues.startDate = object.startDate; | |
137 | - myValues.stopDate = object.stopDate; | |
138 | - myValues.durationDay = object.durationDay; | |
139 | - myValues.durationHour = object.durationHour; | |
140 | - myValues.durationMin = object.durationMin; | |
141 | - myValues.durationSec = object.durationSec; | |
142 | - } | |
143 | - } | |
144 | - }); | |
145 | - | |
146 | - myValues.name = fullObject.get('name'); | |
147 | - return myValues; | |
148 | - }, | |
65 | + decodeObject: function(obj) { | |
66 | + var myValues = new Object(); | |
67 | + myValues.list=[]; | |
68 | + | |
69 | + if (!obj) { | |
70 | + var fullObject = this.get('realLinkedNode').get('object'); | |
71 | + } | |
72 | + else { | |
73 | + var fullObject = obj; | |
74 | + } | |
75 | + | |
76 | + fullObject.panels().each(function (panel) { | |
77 | + panel.params().each(function (param) { | |
78 | + var myParam = new Object(); | |
79 | + myParam.paramid = param.get('paramid'); | |
80 | + myParam.type = param.get('type'); | |
81 | + myParam['dim1-index'] = param.get('dim1-index'); | |
82 | + myParam['dim1-sum-type'] = param.get('dim1-sum-type'); | |
83 | + myParam['dim1-min-value'] = param.get('dim1-min-value'); | |
84 | + myParam['dim1-max-value'] = param.get('dim1-max-value'); | |
85 | + myParam['dim1-min-index'] = param.get('dim1-min-index'); | |
86 | + myParam['dim1-max-index'] = param.get('dim1-max-index'); | |
87 | + myParam['dim2-index'] = param.get('dim2-index'); | |
88 | + myParam['dim2-sum-type'] = param.get('dim2-sum-type'); | |
89 | + myParam['dim2-min-value'] = param.get('dim2-min-value'); | |
90 | + myParam['dim2-max-value'] = param.get('dim2-max-value'); | |
91 | + myParam['dim2-min-index'] = param.get('dim2-min-index'); | |
92 | + myParam['dim2-max-index'] = param.get('dim2-max-index'); | |
93 | + myParam.template_args = param.get('template_args'); | |
94 | + if (!param.get('plotonly')) { | |
95 | + myValues.list.push(myParam); | |
96 | + } | |
97 | + else | |
98 | + alert('Parameter '+ myParam.paramid + ' is PlotOnly'); | |
99 | + }); | |
100 | + }); | |
101 | + myValues.timesrc = fullObject.get('timesrc'); | |
102 | + // if there's at least one timeTable name into 'timeTables' collection | |
103 | + if (myValues.timesrc == amdaModel.AmdaTimeObject.inputTimeSrc[0] | |
104 | + && fullObject.get('timeTables') | |
105 | + && fullObject.get('timeTables').length){ | |
106 | + // get complete timeTables collection | |
107 | + var timeTables = fullObject.get('timeTables'); | |
108 | + // init an empty array for timeTables | |
109 | + myValues.timeTables=[]; | |
110 | + // for each interval record | |
111 | + Ext.Array.each(timeTables, function(item, index, all){ | |
112 | + if (!item.$className) { | |
113 | + myValues.timeTables[index] = {timeTableName : item.timeTableName, id : item.id}; | |
114 | + } | |
115 | + // get Json simplified value | |
116 | + else { | |
117 | + myValues.timeTables[index] = item.getJsonValues(); | |
118 | + } | |
119 | + }); | |
120 | + } | |
121 | + else { | |
122 | + myValues.startDate = fullObject.get('startDate'); | |
123 | + myValues.stopDate = fullObject.get('stopDate'); | |
124 | + myValues.durationDay = fullObject.get('durationDay'); | |
125 | + myValues.durationHour = fullObject.get('durationHour'); | |
126 | + myValues.durationMin = fullObject.get('durationMin'); | |
127 | + myValues.durationSec = fullObject.get('durationSec'); | |
128 | + } | |
129 | + | |
130 | + myValues.name = fullObject.get('name'); | |
131 | + return myValues; | |
132 | + }, | |
149 | 133 | |
150 | 134 | encodeObject: function() { |
151 | 135 | }, |
... | ... |
js/app/models/InteractiveNode.js
... | ... | @@ -11,10 +11,6 @@ |
11 | 11 | Ext.define('amdaModel.InteractiveNode', { |
12 | 12 | extend: 'amdaModel.AmdaNode', |
13 | 13 | |
14 | - requires: [ | |
15 | - 'amdaPlotObj.PlotRequestObject' | |
16 | - ], | |
17 | - | |
18 | 14 | fields: [ |
19 | 15 | {name: 'contextNode', type: 'amdaModel.AmdaNode', persist: false}, |
20 | 16 | {name: 'objectDataModel', type: 'string', persist: false}, |
... | ... | @@ -52,7 +48,7 @@ Ext.define('amdaModel.InteractiveNode', { |
52 | 48 | { |
53 | 49 | node.eachChild(function(n) |
54 | 50 | { |
55 | - if (!n.isLoaded() && !n.isRealLeaf()) | |
51 | + if (!n.isLoaded() && !n.isLeaf()) | |
56 | 52 | { |
57 | 53 | nodesToLoad.push(n); |
58 | 54 | me.preloadTreeNode(n,nodesToLoad,onloaded); |
... | ... | @@ -70,7 +66,7 @@ Ext.define('amdaModel.InteractiveNode', { |
70 | 66 | { |
71 | 67 | records.forEach(function (record) |
72 | 68 | { |
73 | - if (!record.isLoaded() && !record.isRealLeaf()) | |
69 | + if (!record.isLoaded() && !record.isLeaf()) | |
74 | 70 | { |
75 | 71 | nodesToLoad.push(record); |
76 | 72 | me.preloadTreeNode(record,nodesToLoad,onloaded); |
... | ... | @@ -100,11 +96,6 @@ Ext.define('amdaModel.InteractiveNode', { |
100 | 96 | } |
101 | 97 | }, |
102 | 98 | |
103 | - isRealLeaf: function() | |
104 | - { | |
105 | - return this.isLeaf(); | |
106 | - }, | |
107 | - | |
108 | 99 | /** |
109 | 100 | * this method is overriden into ExecutableNode to return true |
110 | 101 | */ |
... | ... | @@ -151,7 +142,7 @@ Ext.define('amdaModel.InteractiveNode', { |
151 | 142 | */ |
152 | 143 | rename: function(value,callBackFn) |
153 | 144 | { |
154 | - var dataToSend = {id : this.get('id'), old_name: this.modified.text, name: value, parent : this.data.parentId, leaf: this.isRealLeaf(), nodeType: this.get('nodeType')}; | |
145 | + var dataToSend = {id : this.get('id'), old_name: this.modified.text, name: value, parent : this.data.parentId, leaf: this.isLeaf(), nodeType: this.get('nodeType')}; | |
155 | 146 | AmdaAction.renameObject(dataToSend, callBackFn); |
156 | 147 | }, |
157 | 148 | |
... | ... | @@ -160,7 +151,7 @@ Ext.define('amdaModel.InteractiveNode', { |
160 | 151 | */ |
161 | 152 | renameDD: function(parentId, callBackFn) |
162 | 153 | { |
163 | - var dataToSend = {id : this.get('id'), old_name: this.get('name'), name: this.get('name'), parent : parentId, leaf: this.isRealLeaf(), nodeType: this.get('nodeType')}; | |
154 | + var dataToSend = {id : this.get('id'), old_name: this.get('name'), name: this.get('name'), parent : parentId, leaf: this.isLeaf(), nodeType: this.get('nodeType')}; | |
164 | 155 | AmdaAction.renameObject(dataToSend, callBackFn); |
165 | 156 | }, |
166 | 157 | |
... | ... | @@ -171,7 +162,7 @@ Ext.define('amdaModel.InteractiveNode', { |
171 | 162 | */ |
172 | 163 | isValidName : function(name, callBackFn) |
173 | 164 | { |
174 | - var dataToSend = {name: name, nodeType: this.get('nodeType'), leaf: this.isRealLeaf()}; | |
165 | + var dataToSend = {name: name, nodeType: this.get('nodeType'), leaf: this.isLeaf()}; | |
175 | 166 | AmdaAction.validNameObject(dataToSend, callBackFn); |
176 | 167 | }, |
177 | 168 | |
... | ... | @@ -219,7 +210,12 @@ Ext.define('amdaModel.InteractiveNode', { |
219 | 210 | // reload object into the view of corresponding Module |
220 | 211 | var me = this; |
221 | 212 | myDesktopApp.getLoadedModule(this.get('moduleId'), true, function (module) { |
222 | - module.getUiContent().setObject(me.get('object')); | |
213 | + if (!opt || !opt.plot) { | |
214 | + module.getUiContent().setObject(me.get('object')); | |
215 | + } | |
216 | + else { | |
217 | + module.getUiContent().reloadPlot(me); | |
218 | + } | |
223 | 219 | }); |
224 | 220 | } |
225 | 221 | else { |
... | ... | @@ -459,16 +455,7 @@ Ext.define('amdaModel.InteractiveNode', { |
459 | 455 | { |
460 | 456 | if (node.get('disable')) return; |
461 | 457 | myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.plot.id, true, function (module) { |
462 | - if (!myDesktopApp.desktop.getWindow(myDesktopApp.dynamicModules.plot.id)) { | |
463 | - var request = Ext.create(amdaPlotObj.PlotRequestObject.$className); | |
464 | - var newNode = Ext.create(amdaModel.PlotNode.$className, { object : request }); | |
465 | - // edit newNode into Plot Module with node as contextNode | |
466 | - newNode.editInModule(); | |
467 | - if((node.get('globalStart') != null) && (node.get('globalStop') != null) && node.get('globalStart') != 'depending on mission' && node.get('isParameter')) { | |
468 | - module.getUiContent().setTimeFromData(node.getTimeFromNode(node)); | |
469 | - } | |
470 | - } | |
471 | - module.getUiContent().addParameter(node); | |
458 | + module.addParameter(node); | |
472 | 459 | }); |
473 | 460 | }, |
474 | 461 | |
... | ... | @@ -530,7 +517,7 @@ Ext.define('amdaModel.InteractiveNode', { |
530 | 517 | |
531 | 518 | deleteNode: function() { |
532 | 519 | // if the target is a directory |
533 | - if (!this.isRealLeaf()) { | |
520 | + if (!this.isLeaf()) { | |
534 | 521 | // determine if this directory is empty before launching the delete confirmation method |
535 | 522 | this.isNotEmptyDir(this.confirmDirectoryDeletion); |
536 | 523 | // else (the target is a leaf) |
... | ... | @@ -583,14 +570,14 @@ Ext.define('amdaModel.InteractiveNode', { |
583 | 570 | */ |
584 | 571 | realDelete : function() |
585 | 572 | { |
586 | - AmdaAction.deleteObject({id: this.get('id'), leaf: this.isRealLeaf(), nodeType: this.get('nodeType')}, function(res,e){ | |
573 | + AmdaAction.deleteObject({id: this.get('id'), leaf: this.isLeaf(), nodeType: this.get('nodeType')}, function(res,e){ | |
587 | 574 | //TODO proper errors handling |
588 | 575 | // node deletion in tree |
589 | 576 | if (res) { // if success |
590 | 577 | if (res.id) { |
591 | 578 | //Ext.Msg.show({title:'Warning', msg: 'Requests with parameter '+node.data.text+' are deleted', icon: Ext.MessageBox.ERROR, buttons: Ext.Msg.OK}); |
592 | 579 | if (this.parentNode) { |
593 | - if (this.isRealLeaf()){ | |
580 | + if (this.isLeaf()){ | |
594 | 581 | var moduleId = this.get('moduleId'); |
595 | 582 | // if really interactive node |
596 | 583 | if (moduleId) { |
... | ... |
... | ... | @@ -0,0 +1,25 @@ |
1 | +/** | |
2 | + * Project : AMDA-NG4 | |
3 | + * Name : MultiplotNode.js | |
4 | + * @class amdaModel.MutiplotNode | |
5 | + * @extends amdaModel.ExecutableNode | |
6 | + * @brief Basic Model of Node corresponding to a multi-plot request | |
7 | + * @author Benjamin Renard | |
8 | + */ | |
9 | + | |
10 | +Ext.define('amdaModel.MultiplotNode', { | |
11 | + extend: 'amdaModel.ExecutableNode', | |
12 | + | |
13 | + statics: { | |
14 | + nodeType: 'mutiplot' | |
15 | + }, | |
16 | + | |
17 | + constructor : function(config){ | |
18 | + this.callParent(arguments); | |
19 | + this.set('moduleId',myDesktopApp.dynamicModules.plot.id); | |
20 | + this.set('objectDataModel','amdaPlotObj.MultiplotRequestObject'); | |
21 | + this.set('nodeType',this.self.nodeType); | |
22 | + this.set('leaf', true); | |
23 | + } | |
24 | + | |
25 | +}); | |
... | ... |
js/app/models/PlotNode.js
... | ... | @@ -8,49 +8,17 @@ |
8 | 8 | */ |
9 | 9 | |
10 | 10 | Ext.define('amdaModel.PlotNode', { |
11 | - extend: 'amdaModel.ExecutableNode', | |
12 | - | |
13 | - fields : [ | |
14 | - {name : 'tabs', type:'auto', defaultValue:false, persist: false} | |
15 | - ], | |
11 | + extend: 'amdaModel.ExecutableNode', | |
16 | 12 | |
17 | 13 | statics: { |
18 | 14 | nodeType: 'request' |
19 | 15 | }, |
20 | 16 | |
21 | - requires:[ | |
22 | - 'amdaModel.PlotTabNode' | |
23 | - ], | |
24 | - | |
25 | 17 | constructor : function(config){ |
26 | 18 | this.callParent(arguments); |
27 | 19 | this.set('moduleId',myDesktopApp.dynamicModules.plot.id); |
28 | 20 | this.set('objectDataModel','amdaPlotObj.PlotRequestObject'); |
29 | 21 | this.set('nodeType',this.self.nodeType); |
30 | - if (this.get('leaf')) { | |
31 | - this.updateTabs(this.get('tabs')); | |
32 | - } | |
33 | - }, | |
34 | - | |
35 | - updateTabs : function(tabs) { | |
36 | - if (tabs) { | |
37 | - var oneTab = (tabs.length == 1); | |
38 | - this.set('leaf', oneTab); | |
39 | - this.set('iconCls', oneTab ? 'icon-plot-page' : 'icon-plot-pages'); | |
40 | - this.removeAll(); | |
41 | - if (tabs.length > 1) { | |
42 | - var me = this; | |
43 | - Ext.Array.each(tabs, function(tab) { | |
44 | - var tabNode = new amdaModel.PlotTabNode({text: tab.name, tabid: tab.id}); | |
45 | - me.appendChild(tabNode); | |
46 | - }); | |
47 | - } | |
48 | - this.set('tabs', tabs); | |
49 | - } | |
50 | - }, | |
51 | - | |
52 | - specialUpdate : function(res) { | |
53 | - this.updateTabs(res.tabs); | |
54 | 22 | }, |
55 | 23 | |
56 | 24 | allMenuItems : function() { |
... | ... | @@ -76,10 +44,6 @@ Ext.define('amdaModel.PlotNode', { |
76 | 44 | }, { |
77 | 45 | fnId : 'leaf-deleteNode', |
78 | 46 | text : 'Delete Request' |
79 | - }, { | |
80 | - fnId : 'leaf-insertTabs', | |
81 | - text : 'Insert in current Plot Request' | |
82 | - | |
83 | 47 | }]; |
84 | 48 | |
85 | 49 | return menuItems; |
... | ... | @@ -128,35 +92,33 @@ Ext.define('amdaModel.PlotNode', { |
128 | 92 | case 'deleteMulti': |
129 | 93 | this.deleteMulti(); |
130 | 94 | break; |
131 | - case 'insertTabs': | |
132 | - this.insertPlotTabsRequest(); | |
133 | 95 | default: |
134 | 96 | break; |
135 | 97 | } |
136 | 98 | }, |
137 | 99 | |
138 | - isRealLeaf: function() | |
100 | + //Override editInModule | |
101 | + editInModule : function (contextNode, onReady) | |
139 | 102 | { |
140 | - var isFolder = (!this.isLeaf()) && (this.get('tabs') === false); | |
141 | - return !isFolder; | |
103 | + // set the contextNode of this node | |
104 | + this.set('contextNode',contextNode); | |
105 | + | |
106 | + var me = this; | |
107 | + myDesktopApp.getLoadedModule(this.get('moduleId'),true, function (module) { | |
108 | + module.editPlot(me); | |
109 | + }); | |
142 | 110 | }, |
143 | 111 | |
144 | - insertPlotTabsRequest: function() { | |
145 | - var me = this; | |
146 | - AmdaAction.getObject(me.get('id'), me.get('nodeType'), function (result,remoteEvent) { | |
147 | - var paramObj = Ext.create(me.get('objectDataModel'), result); | |
148 | - myDesktopApp.getLoadedModule(me.get('moduleId'), true, function (module) { | |
149 | - module.createWindow(function () { | |
150 | - var uiContent = module.getUiContent(); | |
151 | - if (uiContent != null) { | |
152 | - paramObj.tabs().each(function (tab) { | |
153 | - var tabData = tab.getJsonValues(); | |
154 | - uiContent.insertPlotTab(tabData); | |
155 | - }); | |
156 | - } | |
157 | - }); | |
158 | - }); | |
159 | - }); | |
160 | - } | |
161 | - | |
112 | + //Override rename | |
113 | + rename: function(value,callBackFn) | |
114 | + { | |
115 | + var me = this; | |
116 | + var dataToSend = {id : this.get('id'), old_name: this.modified.text, name: value, parent : this.data.parentId, leaf: this.isLeaf(), nodeType: this.get('nodeType')}; | |
117 | + AmdaAction.renameObject(dataToSend, function(result) { | |
118 | + callBackFn(result); | |
119 | + myDesktopApp.getLoadedModule(me.get('moduleId'),true, function (module) { | |
120 | + module.syncAfterRename(me); | |
121 | + }); | |
122 | + }); | |
123 | + } | |
162 | 124 | }); |
... | ... |
... | ... | @@ -0,0 +1,87 @@ |
1 | +/** | |
2 | + * Project : AMDA-NG | |
3 | + * Name : MultiplotRequestObject.js | |
4 | + * @class amdaPlotObj.MutiplotRequestObject | |
5 | + * @extends amdaModel.AmdaTimeObject | |
6 | + * @brief Multi-Plot Request Business Object Definition | |
7 | + * @author Benjamin Renard | |
8 | + * @version $Id: MultiplotRequestObject.js benjamin $ | |
9 | + ****************************************************************************** | |
10 | + * FT Id : Date : Name - Description | |
11 | + ****************************************************************************** | |
12 | + * : :28/02/2020: BRE - file creation | |
13 | + */ | |
14 | + | |
15 | + | |
16 | +Ext.define('amdaPlotObj.MultiplotRequestObject', { | |
17 | + extend: 'amdaModel.AmdaTimeObject', | |
18 | + idProperty: 'id', | |
19 | + | |
20 | + requires: [ | |
21 | + 'amdaModel.PlotNode', | |
22 | + 'amdaPlotObj.PlotRequestObject' | |
23 | + ], | |
24 | + | |
25 | + hasMany: { | |
26 | + model : 'amdaModel.PlotNode', | |
27 | + name : 'plots', | |
28 | + associationKey:'plots' | |
29 | + }, | |
30 | + | |
31 | + constructor: function(){ | |
32 | + var me = this; | |
33 | + me.callParent(arguments); | |
34 | + }, | |
35 | + | |
36 | + isDirty: function() { | |
37 | + var dirty = false; | |
38 | + this.plots().each(function(plotNode) { | |
39 | + var plotObject = plotNode.get('object'); | |
40 | + if (plotObject && (plotObject.get('id') != '') && plotObject.dirty) { | |
41 | + dirty = true; | |
42 | + } | |
43 | + }); | |
44 | + return dirty; | |
45 | + }, | |
46 | + | |
47 | + createNewPlot: function() { | |
48 | + var plotObject = Ext.create('amdaPlotObj.PlotRequestObject'); | |
49 | + return this.createNewPlotFromObject(plotObject); | |
50 | + }, | |
51 | + | |
52 | + duplicatePlot: function(plotNode) { | |
53 | + var me = this; | |
54 | + var newPlotNode = null; | |
55 | + this.plots().each(function(node, index) { | |
56 | + if (node == plotNode) { | |
57 | + newPlotNode = Ext.create('amdaModel.PlotNode', { | |
58 | + leaf : true | |
59 | + }); | |
60 | + var data = plotNode.get('object').getJsonValues(); | |
61 | + newPlotNode.set('object', Ext.create('amdaPlotObj.PlotRequestObject', data)); | |
62 | + plotNode.get('object').reject(); | |
63 | + me.plots().remove(plotNode); | |
64 | + me.plots().insert(index, [newPlotNode]); | |
65 | + } | |
66 | + }); | |
67 | + return newPlotNode; | |
68 | + }, | |
69 | + | |
70 | + createNewPlotFromObject: function(plotObject) { | |
71 | + var plotNode = Ext.create('amdaModel.PlotNode', { | |
72 | + leaf : true | |
73 | + }); | |
74 | + plotNode.set('object',plotObject); | |
75 | + this.plots().add(plotNode); | |
76 | + return this.plots().getAt(this.plots().count()-1); | |
77 | + }, | |
78 | + | |
79 | + removePlotByInternalId: function(internalId) { | |
80 | + var plotNode = this.plots().data.getByKey(internalId); | |
81 | + if (plotNode) | |
82 | + this.plots().remove(plotNode); | |
83 | + }, | |
84 | + | |
85 | + addPlot: function(plotNode) { | |
86 | + } | |
87 | +}); | |
... | ... |
js/app/models/PlotObjects/PlotRequestObject.js
... | ... | @@ -5,11 +5,12 @@ |
5 | 5 | * @extends amdaModel.AmdaTimeObject |
6 | 6 | * @brief Plot Request Business Object Definition |
7 | 7 | * @author Benjamin Renard |
8 | - * @version $Id: PlotRequestObject.js benjamin $ | |
8 | + * @version $Id: PlotTabObject.js benjamin $ | |
9 | 9 | ****************************************************************************** |
10 | 10 | * FT Id : Date : Name - Description |
11 | 11 | ****************************************************************************** |
12 | - * : :21/07/2015: BRE - file creation | |
12 | + * : :22/07/2015: BRE - file creation | |
13 | + * 20/03/2020: BRE - full rework | |
13 | 14 | */ |
14 | 15 | |
15 | 16 | |
... | ... | @@ -19,122 +20,256 @@ Ext.define('amdaPlotObj.PlotRequestObject', { |
19 | 20 | |
20 | 21 | requires: [ |
21 | 22 | 'amdaPlotObj.PlotObjectConfig', |
22 | - 'amdaPlotObj.PlotTabObject' | |
23 | + 'amdaPlotObj.PlotPanelObject', | |
24 | + 'amdaPlotObj.PlotLayoutVerticalObject', | |
25 | + 'amdaPlotObj.PlotLayoutAutoObject', | |
26 | + 'amdaPlotObj.PlotLayoutManualObject' | |
23 | 27 | ], |
24 | 28 | |
25 | 29 | fields : [ |
26 | - {name: 'id', type:'string'}, | |
30 | + {name: 'tab-index', type: 'int', defaultValue: 0, persist: false}, | |
31 | + {name: 'tab-title', type: 'string', defaultValue: '', persist: false}, | |
32 | + | |
27 | 33 | {name: 'file-format', type: 'string'}, |
28 | 34 | {name: 'file-output', type: 'string'}, |
29 | 35 | {name: 'file-prefix', type: 'string'}, |
30 | 36 | {name: 'one-file-per-interval', type: 'boolean'}, |
31 | - {name: 'last-plotted-tab', type: 'int', defaultValue: 0}, | |
32 | - {name: 'last-tab-id', type: 'int', defaultValue: 0}, | |
33 | - {name: 'active-tab-id', type: 'int', defaultValue: 1} | |
37 | + | |
38 | + {name: 'tree-full-view', type: 'boolean'}, | |
39 | + {name: 'page-node-state', type: 'int', defaultValue: 2}, //0 : collapsed, 1 : expanded, 2 : not set | |
40 | + {name: 'panels-node-state', type: 'int', defaultValue: 2}, //0 : collapsed, 1 : expanded, 2 : not set | |
41 | + | |
42 | + {name: 'page-title-text', type: 'string'}, | |
43 | + {name: 'page-title-color', type: 'string'}, | |
44 | + {name: 'page-title-position', type: 'string'}, | |
45 | + {name: 'page-title-alignment', type: 'string'}, | |
46 | + {name: 'page-title-font-activated', type: 'boolean'}, | |
47 | + {name: 'page-title-font-name', type: 'string'}, | |
48 | + {name: 'page-title-font-size', type: 'int'}, | |
49 | + {name: 'page-title-font-bold', type: 'boolean'}, | |
50 | + {name: 'page-title-font-italic', type: 'boolean'}, | |
51 | + {name: 'page-margins-activated', type: 'boolean'}, | |
52 | + {name: 'page-margin-x', type: 'float'}, | |
53 | + {name: 'page-margin-y', type: 'float'}, | |
54 | + {name: 'page-mode', type: 'string'}, | |
55 | + {name: 'page-orientation', type: 'string'}, | |
56 | + {name: 'page-dimension', type: 'string'}, | |
57 | + {name: 'page-superpose-mode', type: 'boolean'}, | |
58 | + {name: 'page-font-activated', type: 'boolean'}, | |
59 | + {name: 'page-font-name', type: 'string'}, | |
60 | + {name: 'page-font-size', type: 'int'}, | |
61 | + {name: 'page-font-bold', type: 'boolean'}, | |
62 | + {name: 'page-font-italic', type: 'boolean'}, | |
63 | + {name: 'page-layout-type', type: 'string'}, | |
64 | + {name: 'page-layout-object', type: 'auto', defaultValue: null}, | |
65 | + {name: 'last-panel-id', type: 'int', defaultValue: 0} | |
34 | 66 | ], |
35 | 67 | |
36 | - hasMany: { | |
37 | - model : 'amdaPlotObj.PlotTabObject', | |
38 | - name : 'tabs', | |
39 | - associationKey:'tabs' | |
40 | - }, | |
68 | + associations : [ | |
69 | + { | |
70 | + type : 'hasMany', | |
71 | + model : 'amdaPlotObj.PlotPanelObject', | |
72 | + name : 'panels' | |
73 | + } | |
74 | + ], | |
41 | 75 | |
42 | 76 | constructor: function(){ |
43 | - var me = this; | |
44 | - me.callParent(arguments); | |
45 | - if ((arguments.length > 0) && arguments[0] && arguments[0].tabs) | |
77 | + var me = this; | |
78 | + me.callParent(arguments); | |
79 | + if ((arguments.length > 0) && arguments[0]) | |
46 | 80 | { |
47 | - if (arguments[0].tabs) | |
48 | - me.loadTabs(arguments[0].tabs); | |
81 | + if (arguments[0].panels) | |
82 | + me.loadPanels(arguments[0].panels); | |
83 | + if (arguments[0]['page-layout-object']) | |
84 | + me.loadLayoutObject(arguments[0]['page-layout-object']); | |
49 | 85 | } |
50 | 86 | else |
51 | 87 | { |
52 | 88 | //new object, set default fields values |
53 | 89 | me.setDefaultValues(); |
54 | - //New object, force the creation of the first tab | |
55 | - me.createNewTab(); | |
56 | 90 | } |
91 | + this.dirty = false; | |
57 | 92 | }, |
58 | 93 | |
59 | - loadTabs: function(tabs) | |
94 | + loadPanels: function(panels) | |
60 | 95 | { |
61 | - this.tabs().loadData(tabs); | |
96 | + this.panels().loadData(panels); | |
97 | + this.updatePanelIndex(); | |
62 | 98 | }, |
63 | 99 | |
64 | - setDefaultValues: function() | |
100 | + loadLayoutObject: function(layout) | |
65 | 101 | { |
66 | - this.set('file-format', amdaPlotObj.PlotObjectConfig.defaultValues.file.format); | |
67 | - this.set('file-output', amdaPlotObj.PlotObjectConfig.defaultValues.file.output); | |
68 | - this.set('file-prefix', ''); | |
69 | - this.set('one-file-per-interval', amdaPlotObj.PlotObjectConfig.defaultValues.file.oneFilePerInterval); | |
70 | - this.set('last-plotted-tab', 0); | |
71 | - this.set('name', ''); | |
102 | + this.set('page-layout-object', this.createLayoutByType(this.get('page-layout-type'), layout)); | |
103 | + if (this.get('page-layout-object') != null) | |
104 | + this.get('page-layout-object').dirty = false; | |
72 | 105 | }, |
73 | 106 | |
74 | - createNewTab: function() { | |
75 | - this.set('last-tab-id', this.get('last-tab-id') + 1); | |
76 | - var data = {id: this.get('last-tab-id')}; | |
77 | - var applyDefault = true; | |
78 | - if ((arguments.length > 0) && arguments[0]) { | |
79 | - data = arguments[0]; | |
80 | - data['id'] = this.get('last-tab-id'); | |
81 | - applyDefault = false; | |
82 | - } | |
83 | - var recs = this.tabs().add(data); | |
84 | - if (applyDefault) { | |
85 | - recs[0].setDefaultValues(); | |
86 | - } | |
107 | + createNewPanel: function() { | |
108 | + this.set('last-panel-id', this.get('last-panel-id') + 1); | |
109 | + var recs = this.panels().add({id : this.get('last-panel-id')}); | |
110 | + recs[0].setDefaultValues(); | |
87 | 111 | this.dirty = true; |
88 | - return recs[0]; | |
112 | + this.updatePanelIndex(); | |
113 | + return recs[0]; | |
89 | 114 | }, |
90 | 115 | |
91 | - removeTabById: function(tabId) { | |
92 | - //Retrieve tab record | |
93 | - var tabRecord = this.tabs().getById(tabId); | |
94 | - if (tabRecord == null) | |
116 | + removePanelById: function(panelId) { | |
117 | + //Retrieve panel record | |
118 | + var panelRecord = this.panels().getById(panelId); | |
119 | + if (panelRecord == null) | |
95 | 120 | return false; |
96 | - this.tabs().remove(tabRecord); | |
121 | + this.panels().remove(panelRecord); | |
97 | 122 | this.dirty = true; |
123 | + this.updatePanelIndex(); | |
98 | 124 | return true; |
99 | 125 | }, |
100 | 126 | |
101 | - isDirty : function() | |
127 | + updatePanelIndex: function() { | |
128 | + this.panels().each(function(panel, index) { | |
129 | + panel.set('panel-index', index); | |
130 | + }); | |
131 | + }, | |
132 | + | |
133 | + createLayoutByType : function(layoutType, data) | |
102 | 134 | { |
103 | - if (this.get('id') == '') | |
104 | - return false; | |
135 | + //Create layout object in relation with the type | |
136 | + switch (layoutType) | |
137 | + { | |
138 | + case 'vertical' : | |
139 | + return new amdaPlotObj.PlotLayoutVerticalObject(data); | |
140 | + case 'auto' : | |
141 | + return new amdaPlotObj.PlotLayoutAutoObject(data); | |
142 | + case 'manual' : | |
143 | + return new amdaPlotObj.PlotLayoutManualObject(data); | |
144 | + default : | |
145 | + return null; | |
146 | + } | |
147 | + }, | |
148 | + | |
149 | + setLayout: function(layoutType) | |
150 | + { | |
151 | + if (layoutType == this.get('page-layout-type')) | |
152 | + return; | |
153 | + | |
154 | + this.set('page-layout-type', layoutType); | |
155 | + this.set('page-layout-object', this.createLayoutByType(layoutType)); | |
156 | + }, | |
157 | + | |
158 | + setDefaultValues: function() | |
159 | + { | |
160 | + this.set('file-format', amdaPlotObj.PlotObjectConfig.defaultValues.file.format); | |
161 | + this.set('file-output', amdaPlotObj.PlotObjectConfig.defaultValues.file.output); | |
162 | + this.set('file-prefix', ''); | |
163 | + this.set('one-file-per-interval', amdaPlotObj.PlotObjectConfig.defaultValues.file.oneFilePerInterval); | |
164 | + this.set('name', ''); | |
165 | + | |
166 | + this.set('tree-full-view', amdaPlotObj.PlotObjectConfig.defaultValues.tree.fullView); | |
105 | 167 | |
168 | + this.set('page-title-text', ''); | |
169 | + this.set('page-title-color', amdaPlotObj.PlotObjectConfig.defaultValues.page.title.color); | |
170 | + this.set('page-title-position', amdaPlotObj.PlotObjectConfig.defaultValues.page.title.position); | |
171 | + this.set('page-title-alignment', amdaPlotObj.PlotObjectConfig.defaultValues.page.title.alignment); | |
172 | + | |
173 | + this.set('page-title-font-activated', false); | |
174 | + this.set('page-title-font-name', amdaPlotObj.PlotObjectConfig.defaultValues.page.font.name); | |
175 | + this.set('page-title-font-size', amdaPlotObj.PlotObjectConfig.defaultValues.page.font.size); | |
176 | + this.set('page-title-font-bold', false); | |
177 | + this.set('page-title-font-italic', false); | |
178 | + | |
179 | + this.set('page-margins-activated', false); | |
180 | + this.set('page-margin-x', amdaPlotObj.PlotObjectConfig.defaultValues.page.xMargin); | |
181 | + this.set('page-margin-y', amdaPlotObj.PlotObjectConfig.defaultValues.page.yMargin); | |
182 | + this.set('page-mode', amdaPlotObj.PlotObjectConfig.defaultValues.page.mode); | |
183 | + this.set('page-orientation', amdaPlotObj.PlotObjectConfig.defaultValues.page.orientation); | |
184 | + this.set('page-dimension', amdaPlotObj.PlotObjectConfig.defaultValues.page.dimension); | |
185 | + this.set('page-superpose-mode', false); | |
186 | + this.set('page-font-activated', false); | |
187 | + this.set('page-font-name', amdaPlotObj.PlotObjectConfig.defaultValues.page.font.name); | |
188 | + this.set('page-font-size', amdaPlotObj.PlotObjectConfig.defaultValues.page.font.size); | |
189 | + this.set('page-font-bold', false); | |
190 | + this.set('page-font-italic', false); | |
191 | + | |
192 | + this.setLayout(amdaPlotObj.PlotObjectConfig.defaultValues.page.layout.type); | |
193 | + }, | |
194 | + | |
195 | + getPageShortInfo : function() | |
196 | + { | |
197 | + var dimension = amdaPlotObj.PlotObjectConfig.getValueByKey(amdaPlotObj.PlotObjectConfig.availablePageDimensions, this.get('page-dimension')); | |
198 | + var orientation = amdaPlotObj.PlotObjectConfig.getValueByKey(amdaPlotObj.PlotObjectConfig.availablePageOrientations, this.get('page-orientation')); | |
199 | + | |
200 | + var info = dimension+', '+orientation; | |
201 | + if (this.get('page-superpose-mode')) | |
202 | + info += ', Epoch superposed mode'; | |
203 | + return info; | |
204 | + }, | |
205 | + | |
206 | + getLayoutShortInfo : function() | |
207 | + { | |
208 | + var type = amdaPlotObj.PlotObjectConfig.getValueByKey(amdaPlotObj.PlotObjectConfig.availablePageLayouts, this.get('page-layout-type')); | |
209 | + return type; | |
210 | + }, | |
211 | + | |
212 | + isDirty : function() | |
213 | + { | |
106 | 214 | if (this.dirty) |
107 | 215 | return true; |
108 | 216 | |
217 | + if (this.get('page-layout-object') != null) | |
218 | + if (this.get('page-layout-object').dirty) | |
219 | + return true; | |
220 | + | |
109 | 221 | var d = false; |
110 | - this.tabs().each(function (tab, index) { | |
111 | - if (tab.isDirty()) | |
222 | + this.panels().each(function (panel, index) { | |
223 | + if (panel.isDirty()) | |
112 | 224 | d = true; |
113 | 225 | }); |
114 | 226 | return d; |
115 | 227 | }, |
116 | 228 | |
117 | - getJsonValues : function(hasId) | |
229 | + getJsonValues : function() | |
118 | 230 | { |
119 | 231 | var requestValues = new Object(); |
232 | + | |
233 | + requestValues['nodeType'] = 'request'; | |
234 | + requestValues['leaf'] = true; | |
120 | 235 | |
121 | - requestValues['nodeType'] = 'request'; | |
122 | - | |
123 | - if (hasId) { | |
124 | - requestValues['id'] = this.get('id'); | |
125 | - } | |
126 | - | |
127 | - requestValues['leaf'] = true; | |
236 | + requestValues['id'] = this.get('id'); | |
237 | + requestValues['tab-index'] = this.get('tab-index'); | |
238 | + requestValues['tab-title'] = this.get('tab-title'); | |
239 | + requestValues['name'] = this.get('name'); | |
240 | + | |
241 | + requestValues['file-format'] = this.get('file-format'); | |
242 | + requestValues['file-output'] = this.get('file-output'); | |
243 | + requestValues['file-prefix'] = this.get('file-prefix'); | |
244 | + requestValues['one-file-per-interval'] = this.get('one-file-per-interval'); | |
245 | + | |
246 | + requestValues['tree-full-view'] = this.get('tree-full-view'); | |
247 | + requestValues['page-node-state'] = this.get('page-node-state'); | |
248 | + requestValues['panels-node-state'] = this.get('panels-node-state'); | |
249 | + | |
250 | + requestValues['page-title-text'] = this.get('page-title-text'); | |
251 | + requestValues['page-title-color'] = this.get('page-title-color'); | |
252 | + requestValues['page-title-position'] = this.get('page-title-position'); | |
253 | + requestValues['page-title-alignment'] = this.get('page-title-alignment'); | |
254 | + requestValues['page-title-font-activated'] = this.get('page-title-font-activated'); | |
255 | + requestValues['page-title-font-name'] = this.get('page-title-font-name'); | |
256 | + requestValues['page-title-font-size'] = this.get('page-title-font-size'); | |
257 | + requestValues['page-title-font-bold'] = this.get('page-title-font-bold'); | |
258 | + requestValues['page-title-font-italic'] = this.get('page-title-font-italic'); | |
259 | + requestValues['page-margins-activated'] = this.get('page-margins-activated'); | |
260 | + requestValues['page-margin-x'] = this.get('page-margin-x'); | |
261 | + requestValues['page-margin-y'] = this.get('page-margin-y'); | |
262 | + requestValues['page-mode'] = this.get('page-mode'); | |
263 | + requestValues['page-orientation'] = this.get('page-orientation'); | |
264 | + requestValues['page-dimension'] = this.get('page-dimension'); | |
265 | + requestValues['page-superpose-mode'] = this.get('page-superpose-mode'); | |
266 | + requestValues['page-font-activated'] = this.get('page-font-activated'); | |
267 | + requestValues['page-font-name'] = this.get('page-font-name'); | |
268 | + requestValues['page-font-size'] = this.get('page-font-size'); | |
269 | + requestValues['page-font-bold'] = this.get('page-font-bold'); | |
270 | + requestValues['page-font-italic'] = this.get('page-font-italic'); | |
128 | 271 | |
129 | - requestValues['file-format'] = this.get('file-format'); | |
130 | - requestValues['file-output'] = this.get('file-output'); | |
131 | - requestValues['file-prefix'] = this.get('file-prefix'); | |
132 | - requestValues['one-file-per-interval'] = this.get('one-file-per-interval'); | |
133 | - requestValues['last-plotted-tab'] = this.get('last-plotted-tab'); | |
134 | - requestValues['name'] = this.get('name'); | |
135 | - | |
136 | - requestValues['timesrc'] = this.get('timesrc'); | |
137 | - | |
272 | + requestValues['timesrc'] = this.get('timesrc'); | |
138 | 273 | // if there's at least one timeTable name into 'timeTables' collection |
139 | 274 | if (this.get('timesrc') == amdaModel.AmdaTimeObject.inputTimeSrc[0] && this.get('timeTables') && this.get('timeTables').length){ |
140 | 275 | // get complete timeTables collection |
... | ... | @@ -152,23 +287,26 @@ Ext.define('amdaPlotObj.PlotRequestObject', { |
152 | 287 | } |
153 | 288 | }); |
154 | 289 | } else { |
155 | - requestValues['startDate'] = this.get('startDate'); | |
156 | - requestValues['stopDate'] = this.get('stopDate'); | |
157 | - requestValues['durationDay'] = this.get('durationDay'); | |
158 | - requestValues['durationHour'] = this.get('durationHour'); | |
159 | - requestValues['durationMin'] = this.get('durationMin'); | |
160 | - requestValues['durationSec'] = this.get('durationSec'); | |
161 | - } | |
290 | + requestValues['startDate'] = this.get('startDate'); | |
291 | + requestValues['stopDate'] = this.get('stopDate'); | |
292 | + requestValues['durationDay'] = this.get('durationDay'); | |
293 | + requestValues['durationHour'] = this.get('durationHour'); | |
294 | + requestValues['durationMin'] = this.get('durationMin'); | |
295 | + requestValues['durationSec'] = this.get('durationSec'); | |
296 | + } | |
162 | 297 | |
163 | - requestValues['tabs'] = []; | |
164 | - | |
165 | - this.tabs().each(function (tab, index) { | |
166 | - requestValues['tabs'][index] = tab.getJsonValues(); | |
167 | - }); | |
168 | - | |
169 | - requestValues['active-tab-id'] = this.get('active-tab-id'); | |
170 | - requestValues['last-tab-id'] = this.get('last-tab-id'); | |
171 | - | |
172 | - return requestValues; | |
298 | + requestValues['page-layout-type'] = this.get('page-layout-type'); | |
299 | + if (this.get('page-layout-object') != null) | |
300 | + requestValues['page-layout-object'] = this.get('page-layout-object').getJsonValues(); | |
301 | + | |
302 | + requestValues['panels'] = []; | |
303 | + | |
304 | + this.panels().each(function (panel, index) { | |
305 | + requestValues['panels'][index] = panel.getJsonValues(); | |
306 | + }); | |
307 | + | |
308 | + requestValues['last-panel-id'] = this.get('last-panel-id'); | |
309 | + | |
310 | + return requestValues; | |
173 | 311 | } |
174 | 312 | }); |
... | ... |
js/app/models/PlotObjects/PlotTabObject.js deleted
... | ... | @@ -1,294 +0,0 @@ |
1 | -/** | |
2 | - * Project : AMDA-NG | |
3 | - * Name : PlotTabObject.js | |
4 | - * @class amdaPlotObj.PlotTabObject | |
5 | - * @extends amdaModel.AmdaTimeObject | |
6 | - * @brief Plot Tab Business Object Definition | |
7 | - * @author Benjamin Renard | |
8 | - * @version $Id: PlotTabObject.js benjamin $ | |
9 | - ****************************************************************************** | |
10 | - * FT Id : Date : Name - Description | |
11 | - ****************************************************************************** | |
12 | - * : :22/07/2015: BRE - file creation | |
13 | - */ | |
14 | - | |
15 | - | |
16 | -Ext.define('amdaPlotObj.PlotTabObject', { | |
17 | - extend: 'amdaModel.AmdaTimeObject', | |
18 | - idProperty: 'id', | |
19 | - | |
20 | - requires: [ | |
21 | - 'amdaPlotObj.PlotObjectConfig', | |
22 | - 'amdaPlotObj.PlotPanelObject', | |
23 | - 'amdaPlotObj.PlotLayoutVerticalObject', | |
24 | - 'amdaPlotObj.PlotLayoutAutoObject', | |
25 | - 'amdaPlotObj.PlotLayoutManualObject' | |
26 | - ], | |
27 | - | |
28 | - fields : [ | |
29 | - {name: 'id', type: 'int'}, | |
30 | - {name: 'tab-name', type: 'string', defaultValue: ''}, | |
31 | - {name: 'tree-full-view', type: 'boolean'}, | |
32 | - {name: 'multi-plot-linked', type: 'boolean'}, | |
33 | - {name: 'page-node-state', type: 'int', defaultValue: 2}, //0 : collapsed, 1 : expanded, 2 : not set | |
34 | - {name: 'panels-node-state', type: 'int', defaultValue: 2}, //0 : collapsed, 1 : expanded, 2 : not set | |
35 | - {name: 'page-title-text', type: 'string'}, | |
36 | - {name: 'page-title-color', type: 'string'}, | |
37 | - {name: 'page-title-position', type: 'string'}, | |
38 | - {name: 'page-title-alignment', type: 'string'}, | |
39 | - {name: 'page-title-font-activated', type: 'boolean'}, | |
40 | - {name: 'page-title-font-name', type: 'string'}, | |
41 | - {name: 'page-title-font-size', type: 'int'}, | |
42 | - {name: 'page-title-font-bold', type: 'boolean'}, | |
43 | - {name: 'page-title-font-italic', type: 'boolean'}, | |
44 | - {name: 'page-margins-activated', type: 'boolean'}, | |
45 | - {name: 'page-margin-x', type: 'float'}, | |
46 | - {name: 'page-margin-y', type: 'float'}, | |
47 | - {name: 'page-mode', type: 'string'}, | |
48 | - {name: 'page-orientation', type: 'string'}, | |
49 | - {name: 'page-dimension', type: 'string'}, | |
50 | - {name: 'page-superpose-mode', type: 'boolean'}, | |
51 | - {name: 'page-font-activated', type: 'boolean'}, | |
52 | - {name: 'page-font-name', type: 'string'}, | |
53 | - {name: 'page-font-size', type: 'int'}, | |
54 | - {name: 'page-font-bold', type: 'boolean'}, | |
55 | - {name: 'page-font-italic', type: 'boolean'}, | |
56 | - {name: 'page-layout-type', type: 'string'}, | |
57 | - {name: 'page-layout-object', type: 'auto', defaultValue: null}, | |
58 | - {name: 'last-panel-id', type: 'int', defaultValue: 0} | |
59 | - ], | |
60 | - | |
61 | - associations : [ | |
62 | - { | |
63 | - type : 'hasMany', | |
64 | - model : 'amdaPlotObj.PlotPanelObject', | |
65 | - name : 'panels' | |
66 | - }, | |
67 | - { | |
68 | - type : 'belongsTo', | |
69 | - model : 'amdaPlotObj.PlotRequestObject' | |
70 | - } | |
71 | - ], | |
72 | - | |
73 | - constructor: function(){ | |
74 | - var me = this; | |
75 | - me.callParent(arguments); | |
76 | - if ((arguments.length > 0) && arguments[0]) | |
77 | - { | |
78 | - if (arguments[0].panels) | |
79 | - me.loadPanels(arguments[0].panels); | |
80 | - if (arguments[0]['page-layout-object']) | |
81 | - me.loadLayoutObject(arguments[0]['page-layout-object']); | |
82 | - } | |
83 | - else | |
84 | - { | |
85 | - //new object, set default fields values | |
86 | - me.setDefaultValues(); | |
87 | - } | |
88 | - this.dirty = false; | |
89 | - }, | |
90 | - | |
91 | - loadPanels: function(panels) | |
92 | - { | |
93 | - this.panels().loadData(panels); | |
94 | - this.updatePanelIndex(); | |
95 | - }, | |
96 | - | |
97 | - loadLayoutObject: function(layout) | |
98 | - { | |
99 | - this.set('page-layout-object', this.createLayoutByType(this.get('page-layout-type'), layout)); | |
100 | - if (this.get('page-layout-object') != null) | |
101 | - this.get('page-layout-object').dirty = false; | |
102 | - }, | |
103 | - | |
104 | - createNewPanel: function() { | |
105 | - this.set('last-panel-id', this.get('last-panel-id') + 1); | |
106 | - var recs = this.panels().add({id : this.get('last-panel-id')}); | |
107 | - recs[0].setDefaultValues(); | |
108 | - this.dirty = true; | |
109 | - this.updatePanelIndex(); | |
110 | - return recs[0]; | |
111 | - }, | |
112 | - | |
113 | - removePanelById: function(panelId) { | |
114 | - //Retrieve panel record | |
115 | - var panelRecord = this.panels().getById(panelId); | |
116 | - if (panelRecord == null) | |
117 | - return false; | |
118 | - this.panels().remove(panelRecord); | |
119 | - this.dirty = true; | |
120 | - this.updatePanelIndex(); | |
121 | - return true; | |
122 | - }, | |
123 | - | |
124 | - updatePanelIndex: function() { | |
125 | - this.panels().each(function(panel, index) { | |
126 | - panel.set('panel-index', index); | |
127 | - }); | |
128 | - }, | |
129 | - | |
130 | - createLayoutByType : function(layoutType, data) | |
131 | - { | |
132 | - //Create layout object in relation with the type | |
133 | - switch (layoutType) | |
134 | - { | |
135 | - case 'vertical' : | |
136 | - return new amdaPlotObj.PlotLayoutVerticalObject(data); | |
137 | - case 'auto' : | |
138 | - return new amdaPlotObj.PlotLayoutAutoObject(data); | |
139 | - case 'manual' : | |
140 | - return new amdaPlotObj.PlotLayoutManualObject(data); | |
141 | - default : | |
142 | - return null; | |
143 | - } | |
144 | - }, | |
145 | - | |
146 | - setLayout: function(layoutType) | |
147 | - { | |
148 | - if (layoutType == this.get('page-layout-type')) | |
149 | - return; | |
150 | - | |
151 | - this.set('page-layout-type', layoutType); | |
152 | - this.set('page-layout-object', this.createLayoutByType(layoutType)); | |
153 | - }, | |
154 | - | |
155 | - setDefaultValues: function() | |
156 | - { | |
157 | - this.set('tree-full-view', amdaPlotObj.PlotObjectConfig.defaultValues.tree.fullView); | |
158 | - | |
159 | - this.set('multi-plot-linked', false); | |
160 | - | |
161 | - this.set('page-title-text', ''); | |
162 | - this.set('page-title-color', amdaPlotObj.PlotObjectConfig.defaultValues.page.title.color); | |
163 | - this.set('page-title-position', amdaPlotObj.PlotObjectConfig.defaultValues.page.title.position); | |
164 | - this.set('page-title-alignment', amdaPlotObj.PlotObjectConfig.defaultValues.page.title.alignment); | |
165 | - | |
166 | - this.set('page-title-font-activated', false); | |
167 | - this.set('page-title-font-name', amdaPlotObj.PlotObjectConfig.defaultValues.page.font.name); | |
168 | - this.set('page-title-font-size', amdaPlotObj.PlotObjectConfig.defaultValues.page.font.size); | |
169 | - this.set('page-title-font-bold', false); | |
170 | - this.set('page-title-font-italic', false); | |
171 | - | |
172 | - this.set('page-margins-activated', false); | |
173 | - this.set('page-margin-x', amdaPlotObj.PlotObjectConfig.defaultValues.page.xMargin); | |
174 | - this.set('page-margin-y', amdaPlotObj.PlotObjectConfig.defaultValues.page.yMargin); | |
175 | - this.set('page-mode', amdaPlotObj.PlotObjectConfig.defaultValues.page.mode); | |
176 | - this.set('page-orientation', amdaPlotObj.PlotObjectConfig.defaultValues.page.orientation); | |
177 | - this.set('page-dimension', amdaPlotObj.PlotObjectConfig.defaultValues.page.dimension); | |
178 | - this.set('page-superpose-mode', false); | |
179 | - this.set('page-font-activated', false); | |
180 | - this.set('page-font-name', amdaPlotObj.PlotObjectConfig.defaultValues.page.font.name); | |
181 | - this.set('page-font-size', amdaPlotObj.PlotObjectConfig.defaultValues.page.font.size); | |
182 | - this.set('page-font-bold', false); | |
183 | - this.set('page-font-italic', false); | |
184 | - | |
185 | - this.setLayout(amdaPlotObj.PlotObjectConfig.defaultValues.page.layout.type); | |
186 | - }, | |
187 | - | |
188 | - getPageShortInfo : function() | |
189 | - { | |
190 | - var dimension = amdaPlotObj.PlotObjectConfig.getValueByKey(amdaPlotObj.PlotObjectConfig.availablePageDimensions, this.get('page-dimension')); | |
191 | - var orientation = amdaPlotObj.PlotObjectConfig.getValueByKey(amdaPlotObj.PlotObjectConfig.availablePageOrientations, this.get('page-orientation')); | |
192 | - | |
193 | - var info = dimension+', '+orientation; | |
194 | - if (this.get('page-superpose-mode')) | |
195 | - info += ', Epoch superposed mode'; | |
196 | - return info; | |
197 | - }, | |
198 | - | |
199 | - getLayoutShortInfo : function() | |
200 | - { | |
201 | - var type = amdaPlotObj.PlotObjectConfig.getValueByKey(amdaPlotObj.PlotObjectConfig.availablePageLayouts, this.get('page-layout-type')); | |
202 | - return type; | |
203 | - }, | |
204 | - | |
205 | - isDirty : function() | |
206 | - { | |
207 | - if (this.dirty) | |
208 | - return true; | |
209 | - | |
210 | - if (this.get('page-layout-object') != null) | |
211 | - if (this.get('page-layout-object').dirty) | |
212 | - return true; | |
213 | - | |
214 | - var d = false; | |
215 | - this.panels().each(function (panel, index) { | |
216 | - if (panel.isDirty()) | |
217 | - d = true; | |
218 | - }); | |
219 | - return d; | |
220 | - }, | |
221 | - | |
222 | - getJsonValues : function() | |
223 | - { | |
224 | - var tabValues = new Object(); | |
225 | - | |
226 | - tabValues['id'] = this.get('id'); | |
227 | - tabValues['tab-name'] = this.get('tab-name'); | |
228 | - tabValues['tree-full-view'] = this.get('tree-full-view'); | |
229 | - tabValues['multi-plot-linked'] = this.get('multi-plot-linked'); | |
230 | - tabValues['page-node-state'] = this.get('page-node-state'); | |
231 | - tabValues['panels-node-state'] = this.get('panels-node-state'); | |
232 | - tabValues['page-title-text'] = this.get('page-title-text'); | |
233 | - tabValues['page-title-color'] = this.get('page-title-color'); | |
234 | - tabValues['page-title-position'] = this.get('page-title-position'); | |
235 | - tabValues['page-title-alignment'] = this.get('page-title-alignment'); | |
236 | - tabValues['page-title-font-activated'] = this.get('page-title-font-activated'); | |
237 | - tabValues['page-title-font-name'] = this.get('page-title-font-name'); | |
238 | - tabValues['page-title-font-size'] = this.get('page-title-font-size'); | |
239 | - tabValues['page-title-font-bold'] = this.get('page-title-font-bold'); | |
240 | - tabValues['page-title-font-italic'] = this.get('page-title-font-italic'); | |
241 | - tabValues['page-margins-activated'] = this.get('page-margins-activated'); | |
242 | - tabValues['page-margin-x'] = this.get('page-margin-x'); | |
243 | - tabValues['page-margin-y'] = this.get('page-margin-y'); | |
244 | - tabValues['page-mode'] = this.get('page-mode'); | |
245 | - tabValues['page-orientation'] = this.get('page-orientation'); | |
246 | - tabValues['page-dimension'] = this.get('page-dimension'); | |
247 | - tabValues['page-superpose-mode'] = this.get('page-superpose-mode'); | |
248 | - tabValues['page-font-activated'] = this.get('page-font-activated'); | |
249 | - tabValues['page-font-name'] = this.get('page-font-name'); | |
250 | - tabValues['page-font-size'] = this.get('page-font-size'); | |
251 | - tabValues['page-font-bold'] = this.get('page-font-bold'); | |
252 | - tabValues['page-font-italic'] = this.get('page-font-italic'); | |
253 | - | |
254 | - tabValues['timesrc'] = this.get('timesrc'); | |
255 | - // if there's at least one timeTable name into 'timeTables' collection | |
256 | - if (this.get('timesrc') == amdaModel.AmdaTimeObject.inputTimeSrc[0] && this.get('timeTables') && this.get('timeTables').length){ | |
257 | - // get complete timeTables collection | |
258 | - var timeTables = this.get('timeTables'); | |
259 | - // init an empty array for timeTables | |
260 | - tabValues['timeTables'] = []; | |
261 | - // for each interval record | |
262 | - Ext.Array.each(timeTables, function(item, index, all){ | |
263 | - if (!item.$className) { | |
264 | - tabValues['timeTables'][index] = {timeTableName : item.timeTableName, id : item.id}; | |
265 | - } | |
266 | - // get Json simplified value | |
267 | - else { | |
268 | - tabValues['timeTables'][index] = item.getJsonValues(); | |
269 | - } | |
270 | - }); | |
271 | - } else { | |
272 | - tabValues['startDate'] = this.get('startDate'); | |
273 | - tabValues['stopDate'] = this.get('stopDate'); | |
274 | - tabValues['durationDay'] = this.get('durationDay'); | |
275 | - tabValues['durationHour'] = this.get('durationHour'); | |
276 | - tabValues['durationMin'] = this.get('durationMin'); | |
277 | - tabValues['durationSec'] = this.get('durationSec'); | |
278 | - } | |
279 | - | |
280 | - tabValues['page-layout-type'] = this.get('page-layout-type'); | |
281 | - if (this.get('page-layout-object') != null) | |
282 | - tabValues['page-layout-object'] = this.get('page-layout-object').getJsonValues(); | |
283 | - | |
284 | - tabValues['panels'] = []; | |
285 | - | |
286 | - this.panels().each(function (panel, index) { | |
287 | - tabValues['panels'][index] = panel.getJsonValues(); | |
288 | - }); | |
289 | - | |
290 | - tabValues['last-panel-id'] = this.get('last-panel-id'); | |
291 | - | |
292 | - return tabValues; | |
293 | - } | |
294 | -}); |
js/app/models/PlotTabNode.js deleted
... | ... | @@ -1,164 +0,0 @@ |
1 | -/** | |
2 | - * Project : AMDA-NG4 | |
3 | - * Name : PlotTabNode.js | |
4 | - * @class amdaModel.PlotTabNode | |
5 | - * @extends amdaModel.ExecutableNode | |
6 | - * @brief Basic Model of Node corresponding to a tab of a plot request | |
7 | - * @author Benjamin Renard | |
8 | - */ | |
9 | - | |
10 | -Ext.define('amdaModel.PlotTabNode', { | |
11 | - extend: 'amdaModel.ExecutableNode', | |
12 | - | |
13 | - fields : [ | |
14 | - {name : 'tabid', type:'string', defaultValue:'', persist: false} | |
15 | - ], | |
16 | - | |
17 | - statics: { | |
18 | - nodeType: 'plottab' | |
19 | - }, | |
20 | - | |
21 | - constructor : function(config){ | |
22 | - this.callParent(arguments); | |
23 | - this.set('moduleId',myDesktopApp.dynamicModules.plot.id); | |
24 | - //this.set('objectDataModel','amdaPlotObj.PlotRequestObject'); | |
25 | - this.set('nodeType',this.self.nodeType); | |
26 | - this.set('leaf',true); | |
27 | - this.set('iconCls','icon-plot-page'); | |
28 | - }, | |
29 | - | |
30 | - allMenuItems : function() { | |
31 | - var menuItems = | |
32 | - [ | |
33 | - { | |
34 | - fnId : 'ptab-openTab', | |
35 | - text : 'Open in new Plot Request' | |
36 | - }, { | |
37 | - fnId : 'ptab-insertTab', | |
38 | - text : 'Insert in current Plot Request' | |
39 | - }, { | |
40 | - fnId : 'ptab-renameTab', | |
41 | - text : 'Rename Plot Tab' | |
42 | - }]; | |
43 | - | |
44 | - return menuItems; | |
45 | - }, | |
46 | - | |
47 | - allMenuMultiItems : function() { | |
48 | - var menuMulti = [ | |
49 | - ]; | |
50 | - return menuMulti; | |
51 | - }, | |
52 | - | |
53 | - getAllContextMenuItems: function(){ | |
54 | - return this.allMenuItems(); | |
55 | - }, | |
56 | - | |
57 | - getMultiContextMenuItems: function(){ | |
58 | - return this.allMenuMultiItems(); | |
59 | - }, | |
60 | - | |
61 | - onMenuItemClick : function(menu,item,event) { | |
62 | - | |
63 | - var fnId = Ext.util.Format.substr(item.fnId, 5, item.fnId.length); | |
64 | - | |
65 | - switch (fnId) { | |
66 | - | |
67 | - case 'openTab': | |
68 | - this.insertPlotTabRequest(true); | |
69 | - break; | |
70 | - | |
71 | - case 'insertTab': | |
72 | - this.insertPlotTabRequest(false); | |
73 | - break; | |
74 | - | |
75 | - case 'renameTab': | |
76 | - this.renameTab(); | |
77 | - break; | |
78 | - default: | |
79 | - break; | |
80 | - } | |
81 | - }, | |
82 | - | |
83 | - insertPlotTabRequest : function(inNewRequest) { | |
84 | - var me = this; | |
85 | - amdaModel.InteractiveNode.preloadNodes(this.parentNode.getRootNode(), function() { | |
86 | - AmdaAction.getObject(me.parentNode.get('id'), me.parentNode.get('nodeType'), function (result,remoteEvent) { | |
87 | - var paramObj = Ext.create(me.parentNode.get('objectDataModel'), result); | |
88 | - var tabData = null; | |
89 | - paramObj.tabs().each(function(tab) { | |
90 | - if (tab.get('id') == me.get('tabid')) { | |
91 | - tabData = tab.getJsonValues(); | |
92 | - } | |
93 | - }); | |
94 | - if (tabData != null) { | |
95 | - if (inNewRequest) { | |
96 | - tabData['id'] = 1; | |
97 | - paramObj.set('id',''); | |
98 | - paramObj.set('name', ''); | |
99 | - paramObj.set('folderId', ''); | |
100 | - paramObj.set('active-tab-id', 1); | |
101 | - paramObj.set('last-tab-id', 1); | |
102 | - paramObj.set('last-plotted-tab', 1); | |
103 | - paramObj.loadTabs([tabData]); | |
104 | - myDesktopApp.getLoadedModule(me.get('moduleId'), true, function (module) { | |
105 | - module.setContextNode(me.parentNode.getRootNode()); | |
106 | - module.createWindow(function () { | |
107 | - var uiContent = module.getUiContent(); | |
108 | - if (uiContent != null) { | |
109 | - uiContent.resetProcess(paramObj.getJsonValues()); | |
110 | - } | |
111 | - }); | |
112 | - }); | |
113 | - } | |
114 | - else { | |
115 | - myDesktopApp.getLoadedModule(me.get('moduleId'), true, function (module) { | |
116 | - module.createWindow(function () { | |
117 | - var uiContent = module.getUiContent(); | |
118 | - if (uiContent != null) { | |
119 | - var tabObj = new amdaPlotObj.PlotTabObject(tabData); | |
120 | - uiContent.insertPlotTab(tabData); | |
121 | - } | |
122 | - }); | |
123 | - }); | |
124 | - } | |
125 | - } | |
126 | - }, me); | |
127 | - }); | |
128 | - }, | |
129 | - | |
130 | - editPlotTab : function() { | |
131 | - var me = this; | |
132 | - this.parentNode.editLeaf(function () { | |
133 | - myDesktopApp.getLoadedModule(me.get('moduleId'), true, function (module) { | |
134 | - var uiContent = module.getUiContent(); | |
135 | - if (uiContent != null) { | |
136 | - uiContent.forceActiveTab(me.get('tabid')); | |
137 | - } | |
138 | - }); | |
139 | - }); | |
140 | - }, | |
141 | - | |
142 | - renameTab: function() { | |
143 | - if (this.myGetOwnerTree()) { | |
144 | - var item = this.myGetOwnerTree().getSelectionModel().selected.items[0]; | |
145 | - this.myGetOwnerTree().fireEvent('edition', this.myGetOwnerTree().view, item); | |
146 | - } | |
147 | - }, | |
148 | - | |
149 | - rename: function(value,callBackFn) { | |
150 | - var me = this; | |
151 | - var dataToSend = {id : this.get('tabid'), old_name: this.modified.text, name: value, parent : this.data.parentId, leaf: this.isLeaf(), nodeType: this.get('nodeType')}; | |
152 | - AmdaAction.renameObject(dataToSend, function (result) { | |
153 | - callBackFn(result); | |
154 | - myDesktopApp.getLoadedModule(me.get('moduleId'), true, function (module) { | |
155 | - var uiContent = module.getUiContent(); | |
156 | - if (uiContent != null) { | |
157 | - if ((module.linkedNode != null) && (module.linkedNode.get('id') == dataToSend.parent)) { | |
158 | - uiContent.updatePlotTabName(dataToSend.id, dataToSend.name); | |
159 | - } | |
160 | - } | |
161 | - }); | |
162 | - }); | |
163 | - }, | |
164 | -}); |
js/app/views/ExplorerUI.js
... | ... | @@ -102,7 +102,6 @@ Ext.define('amdaUI.ExplorerUI', { |
102 | 102 | ITEM_KIND_LEAF : 'leaf', |
103 | 103 | ITEM_KIND_DIRE : 'dire', |
104 | 104 | ITEM_KIND_PARA : 'para', |
105 | - ITEM_KIND_PTAB : 'ptab', //plot tab | |
106 | 105 | ITEM_KIND_MISS : 'miss' |
107 | 106 | }, |
108 | 107 | |
... | ... | @@ -354,7 +353,6 @@ Ext.define('amdaUI.ExplorerUI', { |
354 | 353 | case 'remoteParam' : |
355 | 354 | case 'remoteSimuParam' : |
356 | 355 | case 'myData' : |
357 | - case 'plottab' : | |
358 | 356 | return false; |
359 | 357 | default : |
360 | 358 | if (draggedRecord.data.id == targetNode.data.nodeType+'-treeRootNode') |
... | ... | @@ -577,7 +575,7 @@ Ext.define('amdaUI.ExplorerUI', { |
577 | 575 | }); |
578 | 576 | } |
579 | 577 | |
580 | - if (record.isLeaf() || record.data.isParameter || (record.data.tabs && (record.data.tabs.length > 0))) | |
578 | + if (record.isLeaf() || record.data.isParameter) | |
581 | 579 | switch (record.get('nodeType')) |
582 | 580 | { |
583 | 581 | case 'myData' : |
... | ... | @@ -591,9 +589,6 @@ Ext.define('amdaUI.ExplorerUI', { |
591 | 589 | case 'condition' : |
592 | 590 | record.editLeaf(); |
593 | 591 | break; |
594 | - case 'plottab' : | |
595 | - record.editPlotTab(); | |
596 | - break; | |
597 | 592 | case 'localParam' : |
598 | 593 | case 'remoteParam': |
599 | 594 | case 'remoteSimuParam': |
... | ... | @@ -1029,7 +1024,7 @@ Ext.define( 'MyTreeEditor', { |
1029 | 1024 | event.record.commit(); |
1030 | 1025 | var rec = event.record.data; |
1031 | 1026 | // in case of directory |
1032 | - if (!rec.leaf && (rec.nodeType != 'plottab')){ | |
1027 | + if (!rec.leaf){ | |
1033 | 1028 | // set folder's ID returned by server |
1034 | 1029 | rec.id = result.id; |
1035 | 1030 | } |
... | ... |
js/app/views/IntervalUI.js
... | ... | @@ -125,6 +125,9 @@ Ext.define('amdaUI.IntervalUI', { |
125 | 125 | if (stop != null && start != null) { |
126 | 126 | if ( stop <= start ) { |
127 | 127 | form.findField('stopDate').markInvalid('Stop Time must be after Start Time'); |
128 | + } else { | |
129 | + if (!form.findField('stopDate').isValid()) | |
130 | + form.findField('stopDate').clearInvalid(); | |
128 | 131 | } |
129 | 132 | // compute offset |
130 | 133 | var zoneOffset = stop.getTimezoneOffset() - start.getTimezoneOffset(); |
... | ... | @@ -159,6 +162,21 @@ Ext.define('amdaUI.IntervalUI', { |
159 | 162 | ); |
160 | 163 | }, |
161 | 164 | |
165 | + isValid: function() { | |
166 | + var form = this.findParentByType('form').getForm(); | |
167 | + var startField = form.findField('startDate'); | |
168 | + var stopField = form.findField('stopDate'); | |
169 | + if (!startField.isValid() || !stopField.isValid()) | |
170 | + return false; | |
171 | + var start = this.getStartTime(); | |
172 | + var stop = this.getStopTime(); | |
173 | + if ( stop <= start ) { | |
174 | + form.findField('stopDate').markInvalid('Stop Time must be after Start Time'); | |
175 | + return false; | |
176 | + } | |
177 | + return true; | |
178 | + }, | |
179 | + | |
162 | 180 | updateStop: function() { |
163 | 181 | var form = this.findParentByType('form').getForm(); |
164 | 182 | var start = form.findField('startDate').getValue(); |
... | ... |
js/app/views/PlotComponents/PlotElementPanel.js
js/app/views/PlotComponents/PlotExtendShiftPlug.js
... | ... | @@ -21,7 +21,7 @@ Ext.define('amdaPlotComp.PlotExtendShiftPlug', { |
21 | 21 | id: 'plot-extendshift-plug', |
22 | 22 | win : null, |
23 | 23 | form : null, |
24 | - tabId : '', | |
24 | + interactiveId : '', | |
25 | 25 | |
26 | 26 | constructor: function(config) { |
27 | 27 | Ext.apply(this, config); |
... | ... | @@ -39,7 +39,7 @@ Ext.define('amdaPlotComp.PlotExtendShiftPlug', { |
39 | 39 | /** |
40 | 40 | * creation of the window |
41 | 41 | */ |
42 | - show : function(tabId) { | |
42 | + show : function(interactiveId) { | |
43 | 43 | if (!this.win) |
44 | 44 | { |
45 | 45 | this.win = new Ext.Window({ |
... | ... | @@ -77,7 +77,7 @@ Ext.define('amdaPlotComp.PlotExtendShiftPlug', { |
77 | 77 | Ext.PluginManager.register(this); |
78 | 78 | } |
79 | 79 | |
80 | - this.tabId = tabId; | |
80 | + this.interactiveId = interactiveId; | |
81 | 81 | this.win.show(); |
82 | 82 | this.win.setPosition(0,0); |
83 | 83 | }, |
... | ... | @@ -111,7 +111,7 @@ Ext.define('amdaPlotComp.PlotExtendShiftPlug', { |
111 | 111 | var durationUnitField = this.form.getForm().findField('durationUnit'); |
112 | 112 | var duration = this.toSec(durationField.getValue(), durationUnitField.getValue()); |
113 | 113 | if (duration) { |
114 | - this.hostCmp.callInteractivePlot({'action' : actionType, 'tabId' : this.tabId, 'duration' : duration}); | |
114 | + this.hostCmp.callInteractivePlot({'action' : actionType, 'interactiveId' : this.interactiveId, 'duration' : duration}); | |
115 | 115 | } |
116 | 116 | else |
117 | 117 | myDesktopApp.errorMsg('No duration defined'); |
... | ... | @@ -190,4 +190,4 @@ Ext.define('amdaPlotComp.PlotExtendShiftPlug', { |
190 | 190 | }); |
191 | 191 | return this.form; |
192 | 192 | } |
193 | -}); | |
194 | 193 | \ No newline at end of file |
194 | +}); | |
... | ... |
js/app/views/PlotComponents/PlotPreviewUI.js
... | ... | @@ -80,7 +80,7 @@ Ext.define('amdaPlotComp.PlotPreviewUI', { |
80 | 80 | var me = this; |
81 | 81 | |
82 | 82 | this.crtContext = configResult.context; |
83 | - this.tabId = configResult.tabId; | |
83 | + this.interactiveId = configResult.interactiveId; | |
84 | 84 | |
85 | 85 | this.sliderPage = new Ext.slider.Single({ |
86 | 86 | width: 130, |
... | ... | @@ -136,7 +136,7 @@ Ext.define('amdaPlotComp.PlotPreviewUI', { |
136 | 136 | me.hiddenForm.getForm().submit({ |
137 | 137 | params: { |
138 | 138 | sessionId: sessionID, |
139 | - tabId : me.tabId, | |
139 | + interactiveId : me.interactiveId, | |
140 | 140 | preview: true |
141 | 141 | }, |
142 | 142 | success: function(form, action) {}, |
... | ... |
js/app/views/PlotComponents/PlotStandardForm.js
... | ... | @@ -87,7 +87,6 @@ Ext.define('amdaPlotComp.PlotStandardForm', { |
87 | 87 | allowBlank = (typeof allowBlank !== 'undefined') ? allowBlank : false; |
88 | 88 | |
89 | 89 | return { |
90 | - id:name, | |
91 | 90 | xtype: 'numberfield', |
92 | 91 | name: name, |
93 | 92 | fieldLabel: label, |
... | ... | @@ -112,7 +111,6 @@ Ext.define('amdaPlotComp.PlotStandardForm', { |
112 | 111 | allowBlank = (typeof allowBlank !== 'undefined') ? allowBlank : false; |
113 | 112 | |
114 | 113 | return { |
115 | - id:name, | |
116 | 114 | xtype: 'textfield', |
117 | 115 | name: name, |
118 | 116 | fieldLabel: label, |
... | ... |
js/app/views/PlotComponents/PlotTabContent.js
... | ... | @@ -9,86 +9,242 @@ |
9 | 9 | */ |
10 | 10 | |
11 | 11 | Ext.define('amdaPlotComp.PlotTabContent', { |
12 | - extend: 'Ext.form.Panel', | |
13 | - | |
14 | - requires: [ | |
15 | - 'amdaUI.TimeSelectorUI', | |
16 | - 'amdaPlotComp.PlotTree' | |
12 | + extend: 'Ext.form.Panel', | |
13 | + | |
14 | + requires: [ | |
15 | + 'amdaUI.TimeSelectorUI', | |
16 | + 'amdaPlotComp.PlotTree', | |
17 | + 'amdaPlotComp.PlotOutputForm', | |
18 | + 'amdaPlotComp.PlotElementPanel' | |
17 | 19 | ], |
18 | 20 | |
19 | - treePlot: null, | |
20 | - | |
21 | - //Link to the Plot Element Panel | |
22 | - plotElementPanel: null, | |
23 | - | |
24 | - //linkk to the Plot Tab Panel | |
25 | - plotTabPanel : null, | |
26 | - | |
27 | - //Link to the time selctor | |
28 | - timeSelector : null, | |
29 | - | |
30 | - //Tab Object | |
31 | - object: null, | |
21 | + //Link to the Plot Node | |
22 | + plotNode: null, | |
23 | + | |
24 | + //Save initial request data to have the possibility to reject all modifications | |
25 | + initialObjectData: null, | |
26 | + | |
27 | + timeSelector: null, | |
28 | + plotTree: null, | |
29 | + plotElement: null, | |
30 | + plotOutput: null, | |
31 | + | |
32 | + tabIndex: 0, | |
33 | + plotTabPanel: null, | |
32 | 34 | |
33 | 35 | constructor: function(config) { |
34 | 36 | this.init(config); |
35 | 37 | this.callParent(arguments); |
36 | - }, | |
37 | - | |
38 | - setTabObject : function(object) { | |
39 | - this.object = object; | |
40 | - this.treePlot.buildTree(this.object); | |
41 | - this.timeSelector.intervalSel.setInterval(this.object.get('startDate'), this.object.get('stopDate')); | |
42 | - this.addTTs(this.object.get('timeTables')); | |
43 | - }, | |
44 | - | |
45 | - addTTs : function(TTarray) { | |
46 | - // set TTTab | |
47 | - this.timeSelector.setTTTab(TTarray); | |
48 | - }, | |
49 | - | |
50 | - updateLinkedToMultiPlotMode : function (isLinkedToMultiPlotMode) { | |
51 | - this.timeSelector.setVisible(!isLinkedToMultiPlotMode); | |
52 | - this.plotTabPanel.updateLinkedToMultiPlotMode(isLinkedToMultiPlotMode); | |
53 | - }, | |
54 | - | |
55 | - updateTimeObject : function() { | |
56 | - var timeSource = this.timeSelector.getActiveTimeSource(); | |
57 | - var tabForm = this.getForm(); | |
58 | - tabForm.updateRecord(this.object); | |
59 | - this.object.set('timesrc', timeSource); | |
60 | - if (timeSource === amdaModel.AmdaTimeObject.inputTimeSrc[0]) | |
61 | - this.object.set('timeTables',this.timeSelector.TTGrid.getStore().data.items); | |
62 | - }, | |
38 | + }, | |
39 | + | |
40 | + setTime : function(startDate, stopDate) { | |
41 | + this.timeSelector.intervalSel.setInterval(startDate, stopDate); | |
42 | + | |
43 | + }, | |
63 | 44 | |
64 | - init : function(config) { | |
65 | - var me = this; | |
66 | - | |
67 | - this.plotElementPanel = config.plotElementPanel; | |
68 | - this.plotTabPanel = config.plotTabPanel; | |
69 | - | |
70 | - this.timeSelector = new amdaUI.TimeSelectorUI( { id: 'plotTimeSelectorTab' + config.tabId, border : false, flex: 3, collapsible: true, collapseDirection : 'bottom', hidden: true} ); | |
71 | - this.treePlot = new amdaPlotComp.PlotTree({flex: 5.6, plotElementPanel: this.plotElementPanel, plotTabContent: this}); | |
72 | - | |
73 | - var myConf = { | |
74 | - bodyStyle: { background : '#dfe8f6' }, | |
75 | - border : false, | |
76 | - defaults: { | |
77 | - border: false | |
78 | - }, | |
79 | - layout: { | |
80 | - type: 'vbox', | |
81 | - pack: 'start', | |
82 | - align: 'stretch' | |
83 | - }, | |
84 | - items: [ | |
85 | - this.treePlot, | |
86 | - this.timeSelector | |
87 | - ] | |
88 | - }; | |
45 | + updateTimeObject : function() { | |
46 | + var timeSource = this.timeSelector.getActiveTimeSource(); | |
47 | + var tabForm = this.getForm(); | |
48 | + tabForm.updateRecord(this.plotNode.get('object')); | |
49 | + this.plotNode.get('object').set('timesrc', timeSource); | |
50 | + if (timeSource === amdaModel.AmdaTimeObject.inputTimeSrc[0]) | |
51 | + this.plotNode.get('object').set('timeTables',this.timeSelector.TTGrid.getStore().data.items); | |
52 | + }, | |
53 | + | |
54 | + doPlot : function() { | |
55 | + this.plotNode.get('object').set('tab-index', this.tabIndex); | |
56 | + this.plotNode.get('object').set('tab-title', this.getPlotTitle()); | |
57 | + this.plotNode.execute(); | |
58 | + }, | |
59 | + | |
60 | + getPlotTitle: function() { | |
61 | + return (this.plotNode.get('text') != '') ? this.plotNode.get('text') : 'Plot '+(this.tabIndex + 1); | |
62 | + }, | |
63 | + | |
64 | + savePlot : function() { | |
65 | + var me = this; | |
66 | + | |
67 | + var object = this.plotNode.get('object'); | |
68 | + if (!object) | |
69 | + return; | |
70 | + | |
71 | + if ((object.get('id') != '') && (this.plotNode.get('text') == object.get('name'))) { | |
72 | + //update existing request | |
73 | + this.updateTimeObject(); | |
74 | + this.plotNode.update({plot: true, callback: function() { | |
75 | + me.setPlotNode(me.plotNode); //to update initial request data | |
76 | + me.plotTabPanel.updatePlotTabs(); | |
77 | + }}); | |
78 | + return; | |
79 | + } | |
80 | + | |
81 | + //save new request | |
82 | + this.plotNode.isValidName(object.get('name'), function (res) { | |
83 | + if (!res) { | |
84 | + myDesktopApp.errorMsg('Error during object validation'); | |
85 | + return; | |
86 | + } | |
87 | + if (!res.valid) { | |
88 | + if (res.error) { | |
89 | + if (res.error.search('subtree') != -1) { | |
90 | + Ext.Msg.show( { title : 'Warning', | |
91 | + msg: res.error + '<br/>Do you want to overwrite it?', | |
92 | + width: 300, | |
93 | + buttons: Ext.Msg.OKCANCEL, | |
94 | + icon: Ext.Msg.WARNING, | |
95 | + fn : function(btn) { | |
96 | + if (btn == 'cancel') return; | |
97 | + me.saveProcess(true); | |
98 | + }, | |
99 | + scope : me | |
100 | + }); | |
101 | + } | |
102 | + else { | |
103 | + myDesktopApp.errorMsg(res.error); | |
104 | + } | |
105 | + } | |
106 | + else { | |
107 | + myDesktopApp.errorMsg('Invalid object name'); | |
108 | + } | |
109 | + return; | |
110 | + } | |
111 | + me.saveProcess(false); | |
112 | + }); | |
113 | + }, | |
114 | + | |
115 | + saveProcess : function(toRename) { | |
116 | + var me = this; | |
117 | + if (toRename) { | |
118 | + this.updateTimeObject(); | |
119 | + this.plotNode.update({plot: true, callback: function() { | |
120 | + me.setPlotNode(me.plotNode); //to update initial request data | |
121 | + me.plotTabPanel.updatePlotTabs(); | |
122 | + }}); | |
123 | + } | |
124 | + else { | |
125 | + if (this.plotNode.get('object').get('id') != '') { | |
126 | + //Duplicate request | |
127 | + var plotModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.plot.id); | |
128 | + if (!plotModule) | |
129 | + return; | |
130 | + var newPlotNode = plotModule.linkedNode.get('object').duplicatePlot(this.plotNode); | |
131 | + if (newPlotNode) { | |
132 | + //Reject modifications in old plot node | |
133 | + this.plotNode.reject(); | |
134 | + this.plotNode.set('object', Ext.create('amdaPlotObj.PlotRequestObject', this.initialObjectData)); | |
135 | + //Set new plot node | |
136 | + this.setPlotNode(newPlotNode); | |
137 | + } | |
138 | + } | |
139 | + this.updateTimeObject(); | |
140 | + this.plotNode.create({callback: function() { | |
141 | + me.plotNode.commit(); | |
142 | + me.setPlotNode(me.plotNode); //to update initial request data | |
143 | + me.plotTabPanel.updatePlotTabs(); | |
144 | + me.updateUI(); | |
145 | + }}); | |
146 | + } | |
147 | + }, | |
148 | + | |
149 | + getDataProcess : function() { | |
150 | + var downObject = amdaModel.DownloadNode.decodeObject(this.plotNode.get('object')); | |
151 | + amdaModel.DownloadNode.set('object',Ext.create('amdaModel.Download',downObject)); | |
152 | + amdaModel.DownloadNode.editInModule(); | |
153 | + }, | |
154 | + | |
155 | + isValidRequest : function(acceptEmptyTTList = true) { | |
156 | + this.updateTimeObject(); | |
157 | + if (!this.timeSelector.isValid(acceptEmptyTTList)) { | |
158 | + myDesktopApp.errorMsg('Error in Time definition'); | |
159 | + return false; | |
160 | + } | |
161 | + return true; | |
162 | + }, | |
163 | + | |
164 | + updateUI : function() { | |
165 | + this.plotOutput.setObject(this.plotNode.get('object')); | |
166 | + this.timeSelector.intervalSel.setInterval(this.plotNode.get('object').get('startDate'), this.plotNode.get('object').get('stopDate')); | |
167 | + this.timeSelector.intervalSel.updateStop(); | |
168 | + this.timeSelector.setTTTab(this.plotNode.get('object').get('timeTables')); | |
169 | + this.timeSelector.timeSrc.setActiveTab(this.plotNode.get('object').get('timesrc')); | |
170 | + this.treePlot.buildTree(this.plotNode.get('object')); | |
171 | + }, | |
172 | + | |
173 | + setPlotNode : function(plotNode) { | |
174 | + this.initialObjectData = plotNode.get('object').getJsonValues(); | |
175 | + this.plotNode = plotNode; | |
176 | + }, | |
177 | + | |
178 | + init : function(config) { | |
179 | + this.setPlotNode(config.plotNode); | |
180 | + this.tabIndex = config.tabIndex; | |
181 | + this.plotTabPanel = config.plotTabPanel; | |
182 | + | |
183 | + this.timeSelector = new amdaUI.TimeSelectorUI( { id: Ext.id()/*'plotTimeSelectorTab' + this.plotNode.id*/, border : false, flex: 6, collapsible: true, collapseDirection : 'bottom'} ); | |
184 | + this.plotElement = new amdaPlotComp.PlotElementPanel({flex: 11}); | |
185 | + this.treePlot = new amdaPlotComp.PlotTree({flex: 11, plotElementPanel: this.plotElement}); | |
186 | + this.plotOutput = new amdaPlotComp.PlotOutputForm({flex: 6, collapseDirection : 'bottom', collapsible : true }); | |
187 | + | |
188 | + var treePanel = new Ext.form.Panel({ | |
189 | + flex: 1, | |
190 | + layout: { | |
191 | + type: 'vbox', | |
192 | + pack: 'start', | |
193 | + align: 'stretch' | |
194 | + }, | |
195 | + bodyStyle: { background : '#dfe8f6' }, | |
196 | + defaults: { | |
197 | + border: false | |
198 | + }, | |
199 | + items: [ | |
200 | + this.treePlot, | |
201 | + this.timeSelector | |
202 | + ] | |
203 | + }); | |
204 | + | |
205 | + var optionsPanel = new Ext.form.Panel({ | |
206 | + flex: 1, | |
207 | + layout: { | |
208 | + type: 'vbox', | |
209 | + pack: 'start', | |
210 | + align: 'stretch' | |
211 | + }, | |
212 | + bodyStyle: { background : '#dfe8f6' }, | |
213 | + defaults: { | |
214 | + border: false | |
215 | + }, | |
216 | + items: [ | |
217 | + this.plotElement, | |
218 | + this.plotOutput | |
219 | + ] | |
220 | + }); | |
221 | + | |
89 | 222 | |
90 | - Ext.apply (this , Ext.apply (arguments, myConf)); | |
223 | + var myConf = { | |
224 | + bodyStyle: { background : '#dfe8f6' }, | |
225 | + border : false, | |
226 | + defaults: { | |
227 | + border: false | |
228 | + }, | |
229 | + layout: { | |
230 | + type: 'hbox', | |
231 | + pack: 'start', | |
232 | + align: 'stretch' | |
233 | + }, | |
234 | + items: [ | |
235 | + treePanel, | |
236 | + optionsPanel | |
237 | + ], | |
238 | + listeners: { | |
239 | + afterrender: function(comp, eOpts) { | |
240 | + this.updateUI(); | |
241 | + }, | |
242 | + scope: this | |
243 | + } | |
244 | + }; | |
245 | + | |
246 | + Ext.apply (this , Ext.apply (arguments, myConf)); | |
91 | 247 | |
92 | 248 | |
93 | - } | |
94 | -}); | |
95 | 249 | \ No newline at end of file |
250 | + } | |
251 | +}); | |
... | ... |
js/app/views/PlotComponents/PlotTabPanel.js
... | ... | @@ -9,206 +9,178 @@ |
9 | 9 | */ |
10 | 10 | |
11 | 11 | Ext.define('amdaPlotComp.PlotTabPanel', { |
12 | - extend: 'Ext.tab.Panel', | |
12 | + extend: 'Ext.tab.Panel', | |
13 | 13 | |
14 | - requires: [ | |
15 | - 'amdaPlotComp.PlotTabContent' | |
16 | - ], | |
14 | + requires: [ | |
15 | + 'amdaPlotComp.PlotTabContent' | |
16 | + ], | |
17 | 17 | |
18 | - //Link to the Plot Element Panel | |
19 | - plotElementPanel: null, | |
20 | - | |
21 | 18 | //Link to the Plot UI |
22 | 19 | plotUI : null, |
23 | 20 | |
24 | - //Request object | |
25 | - object: null, | |
21 | + //Multiplot object | |
22 | + multiplot_object: null, | |
23 | + | |
24 | + tabbar_destroy : false, | |
26 | 25 | |
27 | - constructor: function(config) { | |
28 | - this.init(config); | |
29 | - this.callParent(arguments); | |
30 | - }, | |
26 | + constructor: function(config) { | |
27 | + this.init(config); | |
28 | + this.callParent(arguments); | |
29 | + }, | |
31 | 30 | |
32 | - setRequestObject: function(object) | |
33 | - { | |
34 | - var me = this; | |
35 | - this.removeAll(); | |
36 | - this.object = object; | |
31 | + setMultiplotObject: function(multiplot_object) { | |
32 | + var me = this; | |
33 | + this.removeAll(); | |
34 | + this.multiplot_object = multiplot_object; | |
37 | 35 | |
38 | - var haveSelectedTab = false; | |
39 | - this.object.tabs().each(function (rec, index) { | |
40 | - if (rec.get('id') == me.object.get('active-tab-id')) { | |
41 | - haveSelectedTab = true; | |
42 | - } | |
43 | - }); | |
36 | + this.multiplot_object.plots().each(function (rec, index) { | |
37 | + this.addPlotNode(rec, index == 0); | |
38 | + }, this); | |
39 | + }, | |
44 | 40 | |
45 | - this.object.tabs().each(function (rec, index) { | |
46 | - var isSelectedTab = haveSelectedTab ? (rec.get('id') == me.object.get('active-tab-id')) : (index == 0); | |
47 | - this.addPlotTab(rec, isSelectedTab); | |
48 | - }, this); | |
49 | - }, | |
41 | + reloadPlot : function(plotNode) { | |
42 | + for (i = 0; i < this.items.getCount(); ++i) | |
43 | + { | |
44 | + var tabItem = this.items.getAt(i); | |
45 | + var tabContent = tabItem.items.getAt(0); | |
46 | + if (plotNode == tabContent.plotNode) { | |
47 | + tabContent.updateUI(); | |
48 | + } | |
49 | + } | |
50 | + }, | |
50 | 51 | |
51 | - addPlotTab: function(tabObject, selectTab) | |
52 | - { | |
53 | - var tabNumber = this.getTabBar().items.getCount(); | |
54 | - var tabContent = new amdaPlotComp.PlotTabContent({plotElementPanel: this.plotElementPanel, plotTabPanel : this, tabId : tabObject.get('id')}); | |
55 | - tabContent.setTabObject(tabObject); | |
56 | - var me = this; | |
57 | - var tabComp = this.add({ | |
58 | - title: (tabObject.get('tab-name') != '') ? tabObject.get('tab-name') : 'Plot '+tabNumber, | |
59 | - closable: true, | |
60 | - layout: 'fit', | |
61 | - bodyStyle: 'background: none', | |
62 | - defaults: { | |
63 | - border: false | |
64 | - }, | |
65 | - items: [ | |
66 | - tabContent | |
67 | - ], | |
68 | - listeners : { | |
69 | - scope : this, | |
70 | - beforeclose: function( tab, eOpts ) { | |
71 | - if (this.items.getCount() == 1) | |
72 | - { | |
73 | - myDesktopApp.warningMsg('You need to keep at least one plot definition'); | |
74 | - return false; | |
75 | - } | |
76 | - return true; | |
77 | - }, | |
78 | - close: function( tab, eOpts ) { | |
79 | - if (tab.items.getAt(0).object) | |
80 | - this.object.removeTabById(tab.items.getAt(0).object.get('id')); | |
81 | - }, | |
82 | - destroy: function(tab, eOpts) { | |
83 | - | |
84 | - this.updatePlotTabs(); | |
85 | - }, | |
86 | - afterrender: function(tab, e0pts) { | |
87 | - if (!tab.tab.el) { | |
88 | - return; | |
89 | - } | |
90 | - tab.tab.el.on('contextmenu', function(e, t, eOpts) { | |
91 | - var menu = new Ext.menu.Menu({ | |
92 | - items: [ | |
93 | - { | |
94 | - text: 'Rename', | |
95 | - handler: function() { | |
96 | - Ext.Msg.prompt('Rename', 'Please enter new plot tab name:', function(btn, text){ | |
97 | - if (btn == 'ok'){ | |
98 | - tabObject.set('tab-name',text); | |
99 | - me.updatePlotTabs(); | |
100 | - } | |
101 | - }, me); | |
102 | - } | |
103 | - } | |
104 | - ] | |
105 | - }); | |
106 | - var position = e.getXY(); | |
107 | - e.stopEvent(); | |
108 | - menu.showAt(position); | |
109 | - },this); | |
110 | - } | |
111 | - } | |
112 | - }); | |
52 | + addPlotNode: function(plotNode, selectTab) | |
53 | + { | |
54 | + for (i = 0; i < this.items.getCount(); ++i) | |
55 | + { | |
56 | + var tabItem = this.items.getAt(i); | |
57 | + var tabContent = tabItem.items.getAt(0); | |
58 | + if (plotNode == tabContent.plotNode) { | |
59 | + //Already opened => select tab | |
60 | + this.setActiveTab(tabItem); | |
61 | + return; | |
62 | + } | |
63 | + } | |
64 | + | |
65 | + var tabNumber = this.getTabBar().items.getCount(); | |
66 | + var tabContent = new amdaPlotComp.PlotTabContent({plotNode: plotNode, tabIndex: tabNumber-1, plotTabPanel: this}); | |
67 | + var me = this; | |
68 | + var tabComp = this.add({ | |
69 | + title: tabContent.getPlotTitle(), | |
70 | + closable: true, | |
71 | + layout: 'fit', | |
72 | + bodyStyle: 'background: none', | |
73 | + defaults: { | |
74 | + border: false | |
75 | + }, | |
76 | + items: [ | |
77 | + tabContent | |
78 | + ], | |
79 | + listeners : { | |
80 | + scope : this, | |
81 | + beforeclose: function( tab, eOpts ) { | |
82 | + if (this.items.getCount() == 1) | |
83 | + { | |
84 | + myDesktopApp.warningMsg('You need to keep at least one plot definition'); | |
85 | + return false; | |
86 | + } | |
87 | + return true; | |
88 | + }, | |
89 | + close: function( tab, eOpts ) { | |
90 | + if (tab.items.getAt(0).plotNode) { | |
91 | + this.multiplot_object.removePlotByInternalId(tab.items.getAt(0).plotNode.internalId); | |
92 | + } | |
93 | + }, | |
94 | + destroy: function(tab, eOpts) { | |
95 | + if (!this.tabbar_destroy) | |
96 | + this.updatePlotTabs(); | |
97 | + } | |
98 | + } | |
99 | + }); | |
113 | 100 | |
114 | - if (selectTab) | |
115 | - this.setActiveTab(tabComp); | |
101 | + if (selectTab) | |
102 | + this.setActiveTab(tabComp); | |
116 | 103 | |
117 | - return tabContent; | |
118 | - }, | |
104 | + return tabContent; | |
105 | + }, | |
119 | 106 | |
120 | - updatePlotTabs: function() | |
121 | - { | |
122 | - var me = this; | |
123 | - var haveSelectedTab = false; | |
124 | - this.object.tabs().each(function (rec, index) { | |
125 | - if (rec.get('id') == me.object.get('active-tab-id')) { | |
126 | - haveSelectedTab = true; | |
127 | - } | |
128 | - }); | |
107 | + updatePlotTabs: function() | |
108 | + { | |
109 | + for (i = 0; i < this.items.getCount(); ++i) | |
110 | + { | |
111 | + var tabItem = this.items.getAt(i); | |
112 | + var tabContent = tabItem.items.getAt(0); | |
113 | + tabContent.tabIndex = i; | |
114 | + var plotNode = tabContent.plotNode; | |
115 | + var title = tabContent.getPlotTitle(); | |
116 | + tabItem.setTitle(title); | |
117 | + if (!this.getActiveTab()) | |
118 | + this.setActiveTab(tabItem); | |
119 | + } | |
120 | + }, | |
129 | 121 | |
130 | - var i = 0; | |
131 | - for (i = 0; i < this.items.getCount(); ++i) | |
132 | - { | |
133 | - var tabItem = this.items.getAt(i); | |
134 | - var tabContent = tabItem.items.getAt(0); | |
135 | - var tabObj = this.object.tabs().getById(tabContent.tabId); | |
136 | - if (!tabObj) { | |
137 | - continue; | |
138 | - } | |
139 | - if (!haveSelectedTab) { | |
140 | - //Set first tab as the selected one | |
141 | - this.setActiveTab(tabItem); | |
142 | - this.object.set('active-tab-id', tabObj.get('id')); | |
143 | - haveSelectedTab = true; | |
144 | - } | |
145 | - var tabNumber = i+1; | |
146 | - tabItem.setTitle((tabObj.get('tab-name') != '') ? tabObj.get('tab-name') : 'Plot '+tabNumber); | |
147 | - tabContent.setTabObject(tabObj); | |
148 | - } | |
149 | - }, | |
150 | - | |
151 | - updateLinkedToMultiPlotMode : function(isLinkedToMultiPlotMode) { | |
152 | - this.plotUI.updateLinkedToMultiPlotMode(isLinkedToMultiPlotMode); | |
153 | - }, | |
154 | - | |
155 | - updateTimeObject : function() { | |
156 | - for (i = 0; i < this.items.getCount(); ++i) | |
157 | - { | |
158 | - this.items.getAt(i).items.getAt(0).updateTimeObject(); | |
159 | - } | |
160 | - }, | |
122 | + updateRequestName: function(renamedNode) | |
123 | + { | |
124 | + for (i = 0; i < this.items.getCount(); ++i) | |
125 | + { | |
126 | + var tabItem = this.items.getAt(i); | |
127 | + var tabContent = tabItem.items.getAt(0); | |
128 | + var plotNode = tabContent.plotNode; | |
129 | + if (plotNode == renamedNode) { | |
130 | + plotNode.get('object').set('name', renamedNode.get('text')); | |
131 | + tabContent.updateUI(); | |
132 | + } | |
133 | + } | |
134 | + }, | |
135 | + | |
136 | + getCurrentPlotTabContent : function() { | |
137 | + if (this.getActiveTab()) | |
138 | + return this.getActiveTab().child(); | |
139 | + return null; | |
140 | + }, | |
161 | 141 | |
162 | - getTreeFromPlotTab: function(plotTab) | |
163 | - { | |
164 | - return plotTab.child().treePlot; | |
165 | - }, | |
142 | + updateTimeObjects : function() { | |
143 | + for (i = 0; i < this.items.getCount(); ++i) | |
144 | + { | |
145 | + this.items.getAt(i).items.getAt(0).updateTimeObject(); | |
146 | + } | |
147 | + }, | |
166 | 148 | |
167 | - getSelectedTabId: function() | |
168 | - { | |
169 | - if (this.getActiveTab()) | |
170 | - return this.getActiveTab().child().tabId; | |
171 | - return 0; | |
172 | - }, | |
149 | + getTreeFromPlotTab: function(plotTab) | |
150 | + { | |
151 | + return plotTab.child().treePlot; | |
152 | + }, | |
173 | 153 | |
174 | - init : function(config) { | |
175 | - var me = this; | |
176 | - | |
177 | - this.plotElementPanel = config.plotElementPanel; | |
178 | - this.plotUI = config.plotUI; | |
179 | - | |
180 | - var myConf = { | |
181 | - plain: true, | |
182 | - bodyStyle: { background : '#dfe8f6' }, | |
183 | - border : false, | |
184 | - defaults: { | |
185 | - border: false | |
186 | - }, | |
187 | - tabBar:{ | |
188 | - items:[ | |
189 | - { | |
190 | - text:'+', | |
191 | - closable: false, | |
192 | - handler:function(btn,e){ | |
193 | - var tabContent = me.addPlotTab(me.object.createNewTab(), true); | |
194 | - } | |
195 | - }] | |
196 | - }, | |
197 | - | |
198 | - listeners: { | |
199 | - tabchange: function(tabPanel, newCard, oldCard, eOpts ) { | |
200 | - var newCardTree = this.getTreeFromPlotTab(newCard); | |
201 | - var selectedNode = newCardTree.getSelectedNode(); | |
202 | - if (selectedNode == null) | |
203 | - me.plotElementPanel.resetElement(); | |
204 | - else | |
205 | - me.plotElementPanel.setElement(selectedNode.type,selectedNode.object, newCardTree); | |
206 | - newCardTree.updateLinkedToMultiPlotMode(); | |
207 | - }, | |
208 | - scope: me | |
209 | - } | |
210 | - }; | |
211 | - | |
212 | - Ext.apply (this , Ext.apply (arguments, myConf)); | |
213 | - } | |
154 | + init : function(config) { | |
155 | + var me = this; | |
156 | + | |
157 | + this.plotUI = config.plotUI; | |
158 | + | |
159 | + var myConf = { | |
160 | + plain: true, | |
161 | + bodyStyle: { background : '#dfe8f6' }, | |
162 | + border : false, | |
163 | + defaults: { | |
164 | + border: false | |
165 | + }, | |
166 | + tabBar:{ | |
167 | + items:[ | |
168 | + { | |
169 | + text:'+', | |
170 | + closable: false, | |
171 | + handler:function(btn,e){ | |
172 | + var tabContent = me.addPlotNode(me.multiplot_object.createNewPlot(), true); | |
173 | + } | |
174 | + } | |
175 | + ], | |
176 | + listeners: { | |
177 | + beforedestroy: function(tabbar, eOpts) { | |
178 | + me.tabbar_destroy = true; | |
179 | + } | |
180 | + } | |
181 | + } | |
182 | + }; | |
183 | + | |
184 | + Ext.apply (this , Ext.apply (arguments, myConf)); | |
185 | + } | |
214 | 186 | }); |
... | ... |
js/app/views/PlotComponents/PlotTree.js
... | ... | @@ -18,7 +18,6 @@ Ext.define('amdaPlotComp.PlotTree', { |
18 | 18 | //Link to the combo box to define the use of the simplified view |
19 | 19 | simplifiedViewCombo : null, |
20 | 20 | |
21 | - //Link to the combo to attach the tab to the multi plot mode | |
22 | 21 | |
23 | 22 | //Link to the Plot Element Panel |
24 | 23 | plotElementPanel: null, |
... | ... | @@ -63,7 +62,6 @@ Ext.define('amdaPlotComp.PlotTree', { |
63 | 62 | this.suspendLayouts(); |
64 | 63 | this.buildPanelsNode(); |
65 | 64 | this.simplifiedViewCombo.setValue(this.tabObject.get('tree-full-view')); |
66 | - this.linkToMultiPlotCombo.setValue(this.tabObject.get('multi-plot-linked')); | |
67 | 65 | this.resumeLayouts(true); |
68 | 66 | }, |
69 | 67 | |
... | ... | @@ -853,10 +851,6 @@ Ext.define('amdaPlotComp.PlotTree', { |
853 | 851 | } |
854 | 852 | }, |
855 | 853 | |
856 | - updateLinkedToMultiPlotMode : function() { | |
857 | - this.plotTabContent.updateLinkedToMultiPlotMode(this.tabObject.get('multi-plot-linked')); | |
858 | - }, | |
859 | - | |
860 | 854 | init : function(config) { |
861 | 855 | var me = this; |
862 | 856 | |
... | ... | @@ -891,21 +885,6 @@ Ext.define('amdaPlotComp.PlotTree', { |
891 | 885 | } |
892 | 886 | }); |
893 | 887 | |
894 | - this.linkToMultiPlotCombo = Ext.create('Ext.form.field.Checkbox', { | |
895 | - xtype: 'checkbox', | |
896 | - boxLabel: 'Link to MultiPlot', | |
897 | - listeners: { | |
898 | - change: function(combo, newValue, oldValue, eOpts) { | |
899 | - if (this.tabObject) | |
900 | - { | |
901 | - this.tabObject.set('multi-plot-linked', newValue); | |
902 | - this.updateLinkedToMultiPlotMode(); | |
903 | - } | |
904 | - }, | |
905 | - scope: this | |
906 | - } | |
907 | - }); | |
908 | - | |
909 | 888 | var myConf = { |
910 | 889 | store: store, |
911 | 890 | rootVisible: false, |
... | ... | @@ -959,8 +938,6 @@ Ext.define('amdaPlotComp.PlotTree', { |
959 | 938 | scope: this |
960 | 939 | }, |
961 | 940 | '-', '->', |
962 | - this.linkToMultiPlotCombo, | |
963 | - ' ', | |
964 | 941 | this.simplifiedViewCombo |
965 | 942 | ] |
966 | 943 | }; |
... | ... |
js/app/views/PlotComponents/PlotZoomPlug.js
... | ... | @@ -26,7 +26,7 @@ Ext.define('amdaPlotComp.PlotZoomPlug', { |
26 | 26 | win: null, |
27 | 27 | form: null, |
28 | 28 | zoomType: '', |
29 | - tabId: '', | |
29 | + interactiveId: '', | |
30 | 30 | panelId: -1, |
31 | 31 | |
32 | 32 | linkedTTCatNode: null, |
... | ... | @@ -101,7 +101,7 @@ Ext.define('amdaPlotComp.PlotZoomPlug', { |
101 | 101 | /** |
102 | 102 | * creation of the window |
103 | 103 | */ |
104 | - show: function (tabId, zoomType, panelId) { | |
104 | + show: function (interactiveId, zoomType, panelId) { | |
105 | 105 | if (!this.win) { |
106 | 106 | this.win = new Ext.Window({ |
107 | 107 | id: 'plot-zoom-win-' + this.hostCmp.ownerCt.getId(), // Plot window ID |
... | ... | @@ -136,7 +136,7 @@ Ext.define('amdaPlotComp.PlotZoomPlug', { |
136 | 136 | Ext.PluginManager.register(this); |
137 | 137 | } |
138 | 138 | |
139 | - this.tabId = tabId; | |
139 | + this.interactiveId = interactiveId; | |
140 | 140 | this.updateWinByType(zoomType, panelId); |
141 | 141 | this.win.show(); |
142 | 142 | this.win.setPosition(0, 0); |
... | ... | @@ -407,7 +407,7 @@ Ext.define('amdaPlotComp.PlotZoomPlug', { |
407 | 407 | |
408 | 408 | this.hostCmp.callInteractivePlot({ |
409 | 409 | 'action': 'zoom', |
410 | - 'tabId': this.tabId, | |
410 | + 'interactiveId': this.interactiveId, | |
411 | 411 | 'panelId': this.panelId, |
412 | 412 | 'axeId': this.zoomType, |
413 | 413 | 'min': minZoom, |
... | ... | @@ -423,7 +423,7 @@ Ext.define('amdaPlotComp.PlotZoomPlug', { |
423 | 423 | handler: function () { |
424 | 424 | this.hostCmp.callInteractivePlot({ |
425 | 425 | 'action': 'undozoom', |
426 | - 'tabId': this.tabId, | |
426 | + 'interactiveId': this.interactiveId, | |
427 | 427 | 'panelId': this.panelId, |
428 | 428 | 'axeId': this.zoomType |
429 | 429 | }); |
... | ... |
js/app/views/PlotTabResultUI.js
... | ... | @@ -22,8 +22,7 @@ Ext.define('amdaUI.PlotTabResultUI', { |
22 | 22 | |
23 | 23 | panelImage : null, |
24 | 24 | crtContext : null, |
25 | - tabId : '', | |
26 | - multiPlotCheck : null, | |
25 | + interactiveId : '', | |
27 | 26 | navToolBar : null, |
28 | 27 | isTTNavBar : false, |
29 | 28 | crtTTFileIndex : 0, |
... | ... | @@ -55,12 +54,6 @@ Ext.define('amdaUI.PlotTabResultUI', { |
55 | 54 | return 'data/'+sessionID +'/RES/'+resultFolder+ '/' + plotFile; |
56 | 55 | }, |
57 | 56 | |
58 | - getInteractiveMultiPlotState: function() { | |
59 | - if (!this.multiPlotCheck) | |
60 | - return false; | |
61 | - return this.multiPlotCheck.getValue(); | |
62 | - }, | |
63 | - | |
64 | 57 | toPixelOnSourceImage : function(value) { |
65 | 58 | return value*100/this.sliderPage.getValue(); |
66 | 59 | }, |
... | ... | @@ -147,7 +140,7 @@ Ext.define('amdaUI.PlotTabResultUI', { |
147 | 140 | me.contextualMenu.add({ |
148 | 141 | text:'Zoom on Time Axis', |
149 | 142 | handler : function(item, e) { |
150 | - zoomPlugin.show(me.tabId, axis.id, panelContext.id); | |
143 | + zoomPlugin.show(me.interactiveId, axis.id, panelContext.id); | |
151 | 144 | zoomPlugin.resetMinMaxValue(); |
152 | 145 | me.panelImage.startZoom(true, 0/*me.toPixelOnResultImage(panelContext.y)*/, size.height /*me.toPixelOnResultImage(panelContext.height)*/, onMinTimeSelection, onMaxTimeSelection); |
153 | 146 | }, |
... | ... | @@ -156,7 +149,7 @@ Ext.define('amdaUI.PlotTabResultUI', { |
156 | 149 | insertIntervalItem = { |
157 | 150 | text:'Insert Interval in TimeTable or Catalog', |
158 | 151 | handler : function(item, e) { |
159 | - zoomPlugin.show(me.tabId, axis.id, panelContext.id); | |
152 | + zoomPlugin.show(me.interactiveId, axis.id, panelContext.id); | |
160 | 153 | zoomPlugin.resetMinMaxValue(); |
161 | 154 | me.panelImage.startZoom(true, 0/*me.toPixelOnResultImage(panelContext.y)*/, size.height /*me.toPixelOnResultImage(panelContext.height)*/, onMinTimeSelection, onMaxTimeSelection); |
162 | 155 | }, |
... | ... | @@ -167,7 +160,7 @@ Ext.define('amdaUI.PlotTabResultUI', { |
167 | 160 | me.contextualMenu.add({ |
168 | 161 | text:'Zoom on Y Left Axis', |
169 | 162 | handler : function(item, e) { |
170 | - zoomPlugin.show(me.tabId, axis.id, panelContext.id); | |
163 | + zoomPlugin.show(me.interactiveId, axis.id, panelContext.id); | |
171 | 164 | zoomPlugin.resetMinMaxValue(); |
172 | 165 | me.panelImage.startZoom(false, me.toPixelOnResultImage(panelContext.x), me.toPixelOnResultImage(panelContext.width), onMinYValueSelection, onMaxYValueSelection); |
173 | 166 | } |
... | ... | @@ -177,7 +170,7 @@ Ext.define('amdaUI.PlotTabResultUI', { |
177 | 170 | me.contextualMenu.add({ |
178 | 171 | text:'Zoom on Y Right Axis', |
179 | 172 | handler : function(item, e) { |
180 | - zoomPlugin.show(me.tabId, axis.id, panelContext.id); | |
173 | + zoomPlugin.show(me.interactiveId, axis.id, panelContext.id); | |
181 | 174 | zoomPlugin.resetMinMaxValue(); |
182 | 175 | me.panelImage.startZoom(false, me.toPixelOnResultImage(panelContext.x), me.toPixelOnResultImage(panelContext.width), onMinYValueSelection, onMaxYValueSelection); |
183 | 176 | } |
... | ... | @@ -187,7 +180,7 @@ Ext.define('amdaUI.PlotTabResultUI', { |
187 | 180 | me.contextualMenu.add({ |
188 | 181 | text:'Zoom on X Axis', |
189 | 182 | handler : function(item, e) { |
190 | - zoomPlugin.show(me.tabId, axis.id, panelContext.id); | |
183 | + zoomPlugin.show(me.interactiveId, axis.id, panelContext.id); | |
191 | 184 | zoomPlugin.resetMinMaxValue(); |
192 | 185 | me.panelImage.startZoom(true, me.toPixelOnResultImage(panelContext.y), me.toPixelOnResultImage(panelContext.height), onMinXValueSelection, onMaxXValueSelection); |
193 | 186 | } |
... | ... | @@ -205,6 +198,11 @@ Ext.define('amdaUI.PlotTabResultUI', { |
205 | 198 | me.contextualMenu.add(insertIntervalItem); |
206 | 199 | } |
207 | 200 | }, |
201 | + | |
202 | + getAxisValue: function(axis, pixelMin, pixelMax, pixelVal) { | |
203 | + var val = amdaPlotComp.PlotContextManager.toAxisValue(axis, pixelMin, pixelMax, pixelVal); | |
204 | + return parseFloat(val).toPrecision(5); | |
205 | + }, | |
208 | 206 | |
209 | 207 | createPlotImage: function(resultFolder, plotFile) { |
210 | 208 | var me = this; |
... | ... | @@ -259,16 +257,16 @@ Ext.define('amdaUI.PlotTabResultUI', { |
259 | 257 | xText = crtTime.toJSON(); |
260 | 258 | break; |
261 | 259 | case 'y-left' : |
262 | - yLeftText = parseFloat(amdaPlotComp.PlotContextManager.toAxisValue(axis, panel.plotArea.y+panel.plotArea.height, panel.plotArea.y, sourceYPos).toFixed(2)); | |
260 | + yLeftText = me.getAxisValue(axis, panel.plotArea.y+panel.plotArea.height, panel.plotArea.y, sourceYPos); | |
263 | 261 | break; |
264 | 262 | case 'y-right' : |
265 | - yRightText = parseFloat(amdaPlotComp.PlotContextManager.toAxisValue(axis, panel.plotArea.y+panel.plotArea.height, panel.plotArea.y, sourceYPos).toFixed(2)); | |
263 | + yRightText = me.getAxisValue(axis, panel.plotArea.y+panel.plotArea.height, panel.plotArea.y, sourceYPos); | |
266 | 264 | break; |
267 | 265 | case 'xaxis_id' : |
268 | - xText = parseFloat(amdaPlotComp.PlotContextManager.toAxisValue(axis, panel.plotArea.x, panel.plotArea.x+panel.plotArea.width, sourceXPos).toFixed(2)); | |
266 | + xText = me.getAxisValue(axis, panel.plotArea.x, panel.plotArea.x+panel.plotArea.width, sourceXPos); | |
269 | 267 | break; |
270 | 268 | case 'epochAxis' : |
271 | - xText = parseFloat(amdaPlotComp.PlotContextManager.toAxisValue(axis, panel.plotArea.x, panel.plotArea.x+panel.plotArea.width, sourceXPos).toFixed(2)); | |
269 | + xText = me.getAxisValue(axis, panel.plotArea.x, panel.plotArea.x+panel.plotArea.width, sourceXPos); | |
272 | 270 | break; |
273 | 271 | } |
274 | 272 | |
... | ... | @@ -312,7 +310,7 @@ Ext.define('amdaUI.PlotTabResultUI', { |
312 | 310 | var crtTimestamp = amdaPlotComp.PlotContextManager.toAxisValue(timeAxisContext, panel.plotArea.x, panel.plotArea.x+panel.plotArea.width, sourceXPos); |
313 | 311 | var crtTime = new Date(crtTimestamp*1000); |
314 | 312 | crtTime = Ext.Date.add(crtTime, Ext.Date.MINUTE, crtTime.getTimezoneOffset()); |
315 | - me.callInteractivePlot({'action' : 'instant', 'tabId' : this.tabId, 'panelId' : panel.id, 'time' : crtTime}); | |
313 | + me.callInteractivePlot({'action' : 'instant', 'interactiveId' : this.interactiveId, 'panelId' : panel.id, 'time' : crtTime}); | |
316 | 314 | }, |
317 | 315 | scope: me |
318 | 316 | }, |
... | ... | @@ -333,7 +331,7 @@ Ext.define('amdaUI.PlotTabResultUI', { |
333 | 331 | handler : function () |
334 | 332 | { |
335 | 333 | var extendShiftPlugin = this.getPlugin('plot-extendshift-plugin-id'); |
336 | - extendShiftPlugin.show(me.tabId); | |
334 | + extendShiftPlugin.show(me.interactiveId); | |
337 | 335 | }, |
338 | 336 | scope: me |
339 | 337 | }, |
... | ... | @@ -358,7 +356,7 @@ Ext.define('amdaUI.PlotTabResultUI', { |
358 | 356 | me.hiddenForm.getForm().submit({ |
359 | 357 | params: { |
360 | 358 | sessionId: sessionID, |
361 | - tabId : me.tabId | |
359 | + interactiveId : me.interactiveId | |
362 | 360 | }, |
363 | 361 | success: function(form, action) {}, |
364 | 362 | failure: function(form, action) {} |
... | ... | @@ -388,13 +386,6 @@ Ext.define('amdaUI.PlotTabResultUI', { |
388 | 386 | |
389 | 387 | this.updateTimeTableInfo(); |
390 | 388 | |
391 | - if (this.multiPlotCheck) | |
392 | - { | |
393 | - this.disableSynchronize = true; | |
394 | - this.multiPlotCheck.setValue(configResult.multiplot); | |
395 | - this.disableSynchronize = false; | |
396 | - } | |
397 | - | |
398 | 389 | this.panelImage.setSrc(this.getImageUrl(configResult.folder, configResult.plotFile)); |
399 | 390 | |
400 | 391 | var size = this.getImageSize(); |
... | ... | @@ -408,15 +399,15 @@ Ext.define('amdaUI.PlotTabResultUI', { |
408 | 399 | if (!this.navToolBar) |
409 | 400 | return; |
410 | 401 | |
411 | - var ttNameField = this.navToolBar.items.get('tt-table-'+this.tabId); | |
402 | + var ttNameField = this.navToolBar.items.get('tt-table-'+this.interactiveId); | |
412 | 403 | if (ttNameField) |
413 | 404 | ttNameField.setValue(this.crtContext.page.ttName); |
414 | 405 | |
415 | - var ttNumberField = this.navToolBar.items.get('tt-number-'+this.tabId); | |
406 | + var ttNumberField = this.navToolBar.items.get('tt-number-'+this.interactiveId); | |
416 | 407 | if (ttNumberField) |
417 | 408 | ttNumberField.setValue(this.crtContext.page.ttIndex + 1); |
418 | 409 | |
419 | - var ttTotalField = this.navToolBar.items.get('tt-total-'+this.tabId); | |
410 | + var ttTotalField = this.navToolBar.items.get('tt-total-'+this.interactiveId); | |
420 | 411 | if (ttTotalField) |
421 | 412 | ttTotalField.setValue(this.crtContext.page.ttNbIntervals); |
422 | 413 | }, |
... | ... | @@ -425,9 +416,8 @@ Ext.define('amdaUI.PlotTabResultUI', { |
425 | 416 | loadMask.show(true); |
426 | 417 | |
427 | 418 | var plotModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.plot.id); |
428 | - var multiPlotState = plotModule.getInteractiveMultiPlotState(); | |
429 | 419 | |
430 | - AmdaAction.interactivePlot(obj, multiPlotState, function (result, e) { | |
420 | + AmdaAction.interactivePlot(obj, function (result, e) { | |
431 | 421 | loadMask.hide(); |
432 | 422 | var t = e.getTransaction(); |
433 | 423 | if (e.status) |
... | ... | @@ -456,28 +446,12 @@ Ext.define('amdaUI.PlotTabResultUI', { |
456 | 446 | if (this.navToolBar) |
457 | 447 | this.navToolBar.removeAll(true); |
458 | 448 | |
459 | - this.multiPlotCheck = Ext.create('Ext.form.field.Checkbox', { | |
460 | - boxLabel : 'Linked to Multi Plot', | |
461 | - scope: this, | |
462 | - handler: function(check, checked) { | |
463 | - if (!this.disableSynchronize) | |
464 | - this.callInteractivePlot({'action' : 'synchronize', 'tabId' : this.tabId}); | |
465 | - }, | |
466 | - scope: this | |
467 | - }); | |
468 | - | |
469 | 449 | var commonItemsCfg = [ |
470 | 450 | '-', |
471 | 451 | { |
472 | 452 | xtype: 'tbspacer', |
473 | 453 | width: 20 |
474 | 454 | }, |
475 | - this.multiPlotCheck, | |
476 | - { | |
477 | - xtype: 'tbspacer', | |
478 | - width: 2 | |
479 | - }, | |
480 | - '-', | |
481 | 455 | '->', |
482 | 456 | { |
483 | 457 | text: 'Get HST Data', |
... | ... | @@ -515,7 +489,7 @@ Ext.define('amdaUI.PlotTabResultUI', { |
515 | 489 | } |
516 | 490 | else |
517 | 491 | --ttintervalIndex; |
518 | - this.callInteractivePlot({'action' : 'goto', 'tabId' : this.tabId, 'ttFileIndex' : ttFileIndex, 'intIndex' : ttintervalIndex}); | |
492 | + this.callInteractivePlot({'action' : 'goto', 'interactiveId' : this.interactiveId, 'ttFileIndex' : ttFileIndex, 'intIndex' : ttintervalIndex}); | |
519 | 493 | } |
520 | 494 | }, |
521 | 495 | '-', |
... | ... | @@ -534,7 +508,7 @@ Ext.define('amdaUI.PlotTabResultUI', { |
534 | 508 | else |
535 | 509 | ++ttintervalIndex; |
536 | 510 | |
537 | - this.callInteractivePlot({'action' : 'goto', 'tabId' : this.tabId, 'ttFileIndex' : ttFileIndex, 'intIndex' : ttintervalIndex}); | |
511 | + this.callInteractivePlot({'action' : 'goto', 'interactiveId' : this.interactiveId, 'ttFileIndex' : ttFileIndex, 'intIndex' : ttintervalIndex}); | |
538 | 512 | } |
539 | 513 | }, |
540 | 514 | '-', |
... | ... | @@ -542,17 +516,17 @@ Ext.define('amdaUI.PlotTabResultUI', { |
542 | 516 | text: 'Go to Interval #', |
543 | 517 | scope: this, |
544 | 518 | handler: function(bt){ |
545 | - var ttGotoNumberField = this.navToolBar.items.get('tt-goto-number-'+this.tabId); | |
519 | + var ttGotoNumberField = this.navToolBar.items.get('tt-goto-number-'+this.interactiveId); | |
546 | 520 | var goToIndex = ttGotoNumberField.getValue() - 1; |
547 | 521 | if ((goToIndex < 0) || (goToIndex >= this.crtContext.page.ttNbIntervals)) |
548 | 522 | myDesktopApp.errorMsg('This interval number is outside of the current timeTable'); |
549 | 523 | else |
550 | - this.callInteractivePlot({'action' : 'goto', 'tabId' : this.tabId, 'ttFileIndex' : this.crtTTFileIndex, 'intIndex' : goToIndex}); | |
524 | + this.callInteractivePlot({'action' : 'goto', 'interactiveId' : this.interactiveId, 'ttFileIndex' : this.crtTTFileIndex, 'intIndex' : goToIndex}); | |
551 | 525 | } |
552 | 526 | }, |
553 | 527 | { |
554 | 528 | xtype: 'numberfield', |
555 | - id : 'tt-goto-number-'+this.tabId, | |
529 | + id : 'tt-goto-number-'+this.interactiveId, | |
556 | 530 | hideTrigger: true, |
557 | 531 | width: 50, |
558 | 532 | minValue: 1 |
... | ... | @@ -562,7 +536,7 @@ Ext.define('amdaUI.PlotTabResultUI', { |
562 | 536 | ' ', |
563 | 537 | { |
564 | 538 | xtype: 'textfield', |
565 | - id: 'tt-table-'+this.tabId, | |
539 | + id: 'tt-table-'+this.interactiveId, | |
566 | 540 | labelAlign: 'right', |
567 | 541 | labelWidth: 30, |
568 | 542 | fieldLabel: 'Table', |
... | ... | @@ -571,7 +545,7 @@ Ext.define('amdaUI.PlotTabResultUI', { |
571 | 545 | }, |
572 | 546 | { |
573 | 547 | xtype: 'textfield', |
574 | - id: 'tt-number-'+this.tabId, | |
548 | + id: 'tt-number-'+this.interactiveId, | |
575 | 549 | labelAlign: 'right', |
576 | 550 | labelWidth: 30, |
577 | 551 | fieldLabel: 'Int #', |
... | ... | @@ -580,7 +554,7 @@ Ext.define('amdaUI.PlotTabResultUI', { |
580 | 554 | }, |
581 | 555 | { |
582 | 556 | xtype: 'textfield', |
583 | - id: 'tt-total-'+this.tabId, | |
557 | + id: 'tt-total-'+this.interactiveId, | |
584 | 558 | labelAlign: 'right', |
585 | 559 | labelWidth: 30, |
586 | 560 | fieldLabel: 'Total', |
... | ... | @@ -595,7 +569,7 @@ Ext.define('amdaUI.PlotTabResultUI', { |
595 | 569 | text: 'Backward', |
596 | 570 | scope: this, |
597 | 571 | handler: function(){ |
598 | - this.callInteractivePlot({'action' : 'backward', 'tabId' : this.tabId}); | |
572 | + this.callInteractivePlot({'action' : 'backward', 'interactiveId' : this.interactiveId}); | |
599 | 573 | } |
600 | 574 | }, |
601 | 575 | '-', |
... | ... | @@ -603,7 +577,7 @@ Ext.define('amdaUI.PlotTabResultUI', { |
603 | 577 | text: '1/2 Backward', |
604 | 578 | scope: this, |
605 | 579 | handler: function(){ |
606 | - this.callInteractivePlot({'action' : 'halfbackward', 'tabId' : this.tabId}); | |
580 | + this.callInteractivePlot({'action' : 'halfbackward', 'interactiveId' : this.interactiveId}); | |
607 | 581 | } |
608 | 582 | }, |
609 | 583 | '-', |
... | ... | @@ -611,7 +585,7 @@ Ext.define('amdaUI.PlotTabResultUI', { |
611 | 585 | text: '1/2 Forward', |
612 | 586 | scope: this, |
613 | 587 | handler: function(){ |
614 | - this.callInteractivePlot({'action' : 'halfforward', 'tabId' : this.tabId}); | |
588 | + this.callInteractivePlot({'action' : 'halfforward', 'interactiveId' : this.interactiveId}); | |
615 | 589 | } |
616 | 590 | }, |
617 | 591 | '-', |
... | ... | @@ -619,7 +593,7 @@ Ext.define('amdaUI.PlotTabResultUI', { |
619 | 593 | text: 'Forward', |
620 | 594 | scope: this, |
621 | 595 | handler: function(){ |
622 | - this.callInteractivePlot({'action' : 'forward', 'tabId' : this.tabId}); | |
596 | + this.callInteractivePlot({'action' : 'forward', 'interactiveId' : this.interactiveId}); | |
623 | 597 | } |
624 | 598 | }]; |
625 | 599 | } |
... | ... | @@ -649,7 +623,7 @@ Ext.define('amdaUI.PlotTabResultUI', { |
649 | 623 | |
650 | 624 | init: function(configResult){ |
651 | 625 | this.crtContext = configResult.context; |
652 | - this.tabId = configResult.tabId; | |
626 | + this.interactiveId = configResult.interactiveId; | |
653 | 627 | |
654 | 628 | this.coordinatesField = new Ext.toolbar.TextItem({ |
655 | 629 | width: 300, |
... | ... | @@ -700,13 +674,6 @@ Ext.define('amdaUI.PlotTabResultUI', { |
700 | 674 | |
701 | 675 | this.updateTimeTableInfo(); |
702 | 676 | |
703 | - if (this.multiPlotCheck) | |
704 | - { | |
705 | - this.disableSynchronize = true; | |
706 | - this.multiPlotCheck.setValue(configResult.multiplot); | |
707 | - this.disableSynchronize = false; | |
708 | - } | |
709 | - | |
710 | 677 | var plotResultTabPanelConfig = { |
711 | 678 | preventHeader : true, |
712 | 679 | autoScroll: true, |
... | ... |
js/app/views/PlotUI.js
... | ... | @@ -10,454 +10,210 @@ |
10 | 10 | |
11 | 11 | |
12 | 12 | Ext.define('amdaUI.PlotUI', { |
13 | - extend: 'Ext.container.Container', | |
14 | - alias: 'widget.newPanelPlot', | |
13 | + extend: 'Ext.container.Container', | |
14 | + alias: 'widget.newPanelPlot', | |
15 | 15 | |
16 | - requires: [ | |
17 | - 'amdaModel.DownloadNode', | |
18 | - 'amdaModel.Download', | |
19 | - 'amdaUI.TimeSelectorUI', | |
20 | - 'amdaPlotComp.PlotTabPanel', | |
21 | - 'amdaPlotComp.PlotOutputForm', | |
22 | - 'amdaPlotComp.PlotElementPanel' | |
16 | + requires: [ | |
17 | + 'amdaModel.DownloadNode', | |
18 | + 'amdaModel.Download', | |
19 | + 'amdaPlotComp.PlotTabPanel' | |
23 | 20 | ], |
24 | 21 | |
25 | - formPanel: null, | |
26 | - | |
27 | - multiPlotIntervalPanel : null, | |
28 | - | |
29 | - plotOutput: null, | |
30 | - | |
31 | - plotTabs : null, | |
32 | - | |
33 | - plotElement : null, | |
34 | - | |
35 | - constructor: function(config) { | |
36 | - this.init(config); | |
37 | - this.callParent(arguments); | |
38 | - if (this.object) | |
39 | - this.setObject(this.object); | |
40 | - }, | |
41 | - | |
42 | - setObject : function(object) { | |
43 | - this.object = object; | |
44 | - this.plotOutput.setObject(this.object); | |
45 | - this.plotTabs.setRequestObject(this.object); | |
46 | - this.timeSelector.intervalSel.setInterval(this.object.get('startDate'), this.object.get('stopDate')); | |
47 | - this.addTTs(this.object.get('timeTables')); | |
48 | - }, | |
49 | - | |
50 | - /** | |
51 | - * overwrite metod called by Save button | |
52 | - */ | |
53 | - overwriteProcess : function(btn) | |
54 | - { | |
55 | - if (btn == 'cancel') return; | |
56 | - | |
57 | - this.saveProcess(true); | |
58 | - }, | |
59 | - | |
60 | - | |
61 | - /** | |
62 | - * save method called by Save button to launch the save process | |
63 | - */ | |
64 | - saveProcess : function(toRename) { | |
65 | - var plotModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.plot.id); | |
66 | - if (!plotModule) | |
67 | - return; | |
68 | - | |
69 | - if (toRename) { | |
70 | - plotModule.linkedNode.set('object',this.object); | |
71 | - plotModule.linkedNode.update(); | |
72 | - } | |
73 | - else { | |
74 | - //Save | |
75 | - if (this.object.get('id') != '') { | |
76 | - //Duplicate request | |
77 | - plotModule.createLinkedNode(); | |
78 | - plotModule.linkedNode.set('object',this.object); | |
79 | - } | |
80 | - plotModule.linkedNode.create(); | |
81 | - } | |
82 | - }, | |
22 | + formPanel: null, | |
23 | + plotTabs : null, | |
24 | + | |
25 | + constructor: function(config) { | |
26 | + this.init(config); | |
27 | + this.callParent(arguments); | |
28 | + if (this.object) | |
29 | + this.setObject(this.object); | |
30 | + }, | |
31 | + | |
32 | + setObject : function(object) { | |
33 | + this.object = object; | |
34 | + if (this.object.plots().count() == 0) { | |
35 | + this.object.createNewPlot(); | |
36 | + } | |
37 | + this.plotTabs.setMultiplotObject(this.object); | |
38 | + }, | |
39 | + | |
40 | + resetProcess : function(){ | |
41 | + var plotModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.plot.id); | |
42 | + plotModule.createLinkedNode(); | |
43 | + var obj = null; | |
44 | + if ((arguments.length > 0) && (arguments[0] != null)) { | |
45 | + obj = arguments[0]; | |
46 | + } | |
47 | + plotModule.createObject(obj); | |
48 | + this.setObject(plotModule.linkedNode.get('object')); | |
49 | + }, | |
50 | + | |
51 | + getDataProcess : function(){ | |
52 | + if ( this.updateObject() ) { | |
53 | + var plotTab = this.plotTabs.getCurrentPlotTabContent(); | |
54 | + if (!plotTab || !plotTab.plotNode) | |
55 | + return; | |
56 | + plotTab.getDataProcess(); | |
57 | + } | |
58 | + }, | |
83 | 59 | |
84 | - resetProcess : function(){ | |
85 | - var plotModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.plot.id); | |
86 | - plotModule.createLinkedNode(); | |
87 | - var obj = null; | |
88 | - if ((arguments.length > 0) && (arguments[0] != null)) { | |
89 | - obj = arguments[0]; | |
90 | - } | |
91 | - plotModule.createObject(obj); | |
92 | - this.setObject(plotModule.linkedNode.get('object')); | |
93 | - }, | |
94 | - | |
95 | - getDataProcess : function(){ | |
96 | - this.updateObject(); | |
97 | - // plot was not called - form only | |
98 | - if (this.object.get('last-plotted-tab') == 0) { | |
99 | - this.object.set('last-plotted-tab', this.plotTabs.getSelectedTabId()); | |
100 | - } | |
101 | - var downObject = amdaModel.DownloadNode.decodeObject(this.object); | |
102 | - amdaModel.DownloadNode.set('object',Ext.create('amdaModel.Download',downObject)); | |
103 | - | |
104 | - amdaModel.DownloadNode.editInModule(); | |
105 | - }, | |
106 | - | |
107 | - addParameter : function(node){ | |
108 | - var crtTree = this.plotTabs.getTreeFromPlotTab(this.plotTabs.getActiveTab()); | |
109 | - crtTree.dropRecord(node,null,'append'); | |
110 | - }, | |
60 | + addParameter : function(node, updateTime){ | |
61 | + var crtTree = this.plotTabs.getTreeFromPlotTab(this.plotTabs.getActiveTab()); | |
62 | + if (crtTree) { | |
63 | + crtTree.dropRecord(node,null,'append'); | |
64 | + if (updateTime) { | |
65 | + if((node.get('globalStart') != null) && (node.get('globalStop') != null) && node.get('globalStart') != 'depending on mission' && node.get('isParameter')) { | |
66 | + this.setTimeFromData(node.getTimeFromNode(node)); | |
67 | + } | |
68 | + } | |
69 | + } | |
70 | + }, | |
71 | + | |
72 | + editPlot : function(plotNode) { | |
73 | + this.plotTabs.addPlotNode(plotNode, true); | |
74 | + }, | |
75 | + | |
76 | + reloadPlot : function(plotNode) { | |
77 | + this.plotTabs.reloadPlot(plotNode); | |
78 | + }, | |
111 | 79 | |
112 | - /** | |
80 | + /** | |
113 | 81 | * plot method called by 'Do Plot' button to launch the plot process |
114 | 82 | */ |
115 | - doPlot : function(){ | |
116 | - | |
117 | - this.updateObject(); | |
118 | - this.object.set('last-plotted-tab', this.plotTabs.getSelectedTabId()); | |
119 | - var plotModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.plot.id); | |
120 | - if (plotModule) | |
121 | - plotModule.linkedNode.execute(); | |
122 | - }, | |
123 | - | |
124 | - /** | |
125 | - * Check if changes were made before closing window | |
126 | - * @return false | |
127 | - */ | |
128 | - fclose : function() { | |
129 | - var module = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.plot.id); | |
130 | - if (module) | |
131 | - module.closeInteractiveSession(); | |
132 | - | |
133 | - return this.object.isDirty(); | |
134 | - }, | |
135 | - | |
136 | - /** | |
137 | - * update time selector of this.object from form | |
138 | - */ | |
139 | - updateObject : function(){ | |
140 | - var timeSource = this.timeSelector.getActiveTimeSource(); | |
141 | - | |
142 | - var multiPlotForm = this.timeSelector.getForm(); | |
143 | - multiPlotForm.updateRecord(this.object); | |
144 | - this.object.set('timesrc', timeSource); | |
145 | - if (timeSource === amdaModel.AmdaTimeObject.inputTimeSrc[0]) | |
146 | - this.object.set('timeTables',this.timeSelector.TTGrid.getStore().data.items); | |
147 | - this.plotTabs.updateTimeObject(); | |
148 | - }, | |
149 | - | |
150 | - addTT : function(newTTName,newTTid,timeSelectorId) { | |
151 | - var crtTimeSelector = Ext.getCmp(timeSelectorId); | |
152 | - if (crtTimeSelector) | |
153 | - crtTimeSelector.addTT(newTTName,newTTid); | |
154 | - }, | |
155 | - | |
156 | - addTTs : function(TTarray) { | |
157 | - // set TTTab | |
158 | - this.timeSelector.setTTTab(TTarray); | |
159 | - }, | |
160 | - | |
161 | - /** | |
162 | - * Set Start-Stop from parameter info (Local & MyData) | |
163 | - */ | |
164 | - setTimeFromData : function(obj) { | |
165 | - if (!obj.start || !obj.stop) | |
166 | - return; | |
167 | - var dateStart = new Date(obj.start.replace(/[T|Z]/g,' ').replace(/\-/g,'\/')); | |
168 | - var dateStop = new Date(obj.stop.replace(/[T|Z]/g,' ').replace(/\-/g,'\/')); | |
169 | - | |
170 | - for (var i = 0; i < this.plotTabs.items.getCount(); ++i) { | |
171 | - var plotTab = this.plotTabs.items.getAt(i).items.getAt(0); | |
172 | - plotTab.items.getAt(1).intervalSel.setInterval(dateStart, dateStop); | |
173 | - //TBD plotTab.updateTimeObject(); | |
174 | - } | |
175 | - | |
176 | - this.timeSelector.intervalSel.setInterval(dateStart, dateStop); | |
177 | - }, | |
178 | - | |
179 | - forceActiveTab : function(tabId) { | |
180 | - for (var i = 0; i < this.plotTabs.items.getCount(); ++i) { | |
181 | - var plotTab = this.plotTabs.items.getAt(i).items.getAt(0); | |
182 | - if (plotTab.tabId == tabId) { | |
183 | - this.plotTabs.setActiveTab(i); | |
184 | - return; | |
185 | - } | |
186 | - } | |
187 | - }, | |
188 | - | |
189 | - updatePlotTabName: function(tabId, name) { | |
190 | - var me = this; | |
191 | - this.object.tabs().each(function (tabObject) { | |
192 | - if (tabId == tabObject.getId()) { | |
193 | - tabObject.set('tab-name', name); | |
194 | - me.plotTabs.updatePlotTabs(); | |
195 | - } | |
196 | - }); | |
197 | - }, | |
198 | - | |
199 | - insertPlotTab : function(tabData) { | |
200 | - var newTab = this.object.createNewTab(tabData); | |
201 | - this.plotTabs.addPlotTab(newTab,true); | |
202 | - }, | |
203 | - | |
204 | - updateLinkedToMultiPlotMode : function(isLinkedToMultiPlotMode) { | |
205 | - this.timeSelector.setVisible(isLinkedToMultiPlotMode); | |
206 | - }, | |
207 | - | |
208 | - keepOnlySelectedTabInObject: function(showWarning, onSuccess) { | |
209 | - if (this.object.tabs().count() == 1) { | |
210 | - if (onSuccess) { | |
211 | - onSuccess(); | |
212 | - } | |
213 | - return; | |
214 | - } | |
215 | - | |
216 | - var me = this; | |
217 | - var removeFunc = function() { | |
218 | - var tabsToRemove = []; | |
219 | - var selectedTabFound = false; | |
220 | - me.object.tabs().each(function(tab) { | |
221 | - if (tab.get('id') != me.object.get('active-tab-id')) { | |
222 | - tabsToRemove.push(tab); | |
223 | - } | |
224 | - else { | |
225 | - selectedTabFound = true; | |
226 | - } | |
227 | - }); | |
228 | - if (!selectedTabFound) { | |
229 | - myDesktopApp.errorMsg('Cannot retrieve selected tab'); | |
230 | - return false; | |
231 | - } | |
232 | - if (tabsToRemove.length > 0) { | |
233 | - me.object.tabs().remove(tabsToRemove); | |
234 | - } | |
235 | - return true; | |
236 | - }; | |
237 | - | |
238 | - if (!showWarning) { | |
239 | - if (removeFunc()) { | |
240 | - if (onSuccess) { | |
241 | - onSuccess(); | |
242 | - } | |
243 | - } | |
244 | - return; | |
245 | - } | |
246 | - | |
247 | - | |
248 | - Ext.Msg.show( { title : 'Warning', | |
249 | - msg: 'Active plot will be saved, but other ones will be lost.<br/>Do you want to continue?', | |
250 | - width: 300, | |
251 | - buttons: Ext.Msg.OKCANCEL, | |
252 | - fn: function(btn) { | |
253 | - if (btn == 'cancel') return; | |
254 | - | |
255 | - if (removeFunc()) { | |
256 | - if (onSuccess) { | |
257 | - onSuccess(); | |
258 | - } | |
259 | - } | |
260 | - return; | |
261 | - }, | |
262 | - scope: me | |
263 | - }); | |
264 | - }, | |
265 | - | |
266 | - savePlotRequest : function(allTabs) { | |
267 | - var plotModule = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.plot.id); | |
268 | - if (!plotModule) | |
269 | - return; | |
270 | - this.updateObject(); | |
271 | - this.object.set('active-tab-id', this.plotTabs.getSelectedTabId()); | |
272 | - var me = this; | |
273 | - | |
274 | - if ((this.object.get('id') != '') && (plotModule.linkedNode.get('text') == this.object.get('name'))) { | |
275 | - //update existing request | |
276 | - if (!allTabs) { | |
277 | - this.keepOnlySelectedTabInObject(true, function() { | |
278 | - plotModule.linkedNode.update(); | |
279 | - }); | |
280 | - } | |
281 | - else { | |
282 | - plotModule.linkedNode.update(); | |
283 | - } | |
284 | - return; | |
285 | - } | |
286 | - | |
287 | - //save new request | |
288 | - var me = this; | |
289 | - plotModule.linkedNode.isValidName(this.object.get('name'), function (res) { | |
290 | - if (!res) { | |
291 | - myDesktopApp.errorMsg('Error during object validation'); | |
292 | - return; | |
293 | - } | |
294 | - if (!res.valid) { | |
295 | - if (res.error) { | |
296 | - if (res.error.search('subtree') != -1) { | |
297 | - Ext.Msg.show( { title : 'Warning', | |
298 | - msg: res.error + '<br/>Do you want to overwrite it?', | |
299 | - width: 300, | |
300 | - buttons: Ext.Msg.OKCANCEL, | |
301 | - icon: Ext.Msg.WARNING, | |
302 | - fn : me.overwriteProcess, | |
303 | - scope : me | |
304 | - }); | |
305 | - } | |
306 | - else { | |
307 | - myDesktopApp.errorMsg(res.error); | |
308 | - } | |
309 | - } | |
310 | - else { | |
311 | - myDesktopApp.errorMsg('Invalid object name'); | |
312 | - } | |
313 | - return; | |
314 | - } | |
315 | - if (!allTabs) { | |
316 | - me.keepOnlySelectedTabInObject((me.object.get('id') == ''), function() { | |
317 | - me.saveProcess(false); | |
318 | - me.setObject(me.object); | |
319 | - }); | |
320 | - } | |
321 | - else { | |
322 | - me.saveProcess(false); | |
323 | - } | |
324 | - }); | |
325 | - }, | |
83 | + doPlot : function(){ | |
84 | + if ( this.updateObject(false) ) { | |
85 | + var plotTab = this.plotTabs.getCurrentPlotTabContent(); | |
86 | + if (plotTab) | |
87 | + plotTab.doPlot(); | |
88 | + } | |
89 | + }, | |
90 | + | |
91 | + /** | |
92 | + * Check if changes were made before closing window | |
93 | + * @return false | |
94 | + */ | |
95 | + fclose : function() { | |
96 | + var module = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.plot.id); | |
97 | + if (module) | |
98 | + module.closeInteractiveSession(); | |
99 | + | |
100 | + return this.object.isDirty(); | |
101 | + }, | |
102 | + | |
103 | + /** | |
104 | + * update time selector of this.object from form | |
105 | + */ | |
106 | + updateObject : function(acceptEmptyTTList = true){ | |
107 | + var plotTab = this.plotTabs.getCurrentPlotTabContent(); | |
108 | + if (plotTab) | |
109 | + return plotTab.isValidRequest(acceptEmptyTTList); | |
110 | + return false; | |
111 | + }, | |
112 | + | |
113 | + updateTabs : function() { | |
114 | + this.plotTabs.updatePlotTabs(); | |
115 | + }, | |
116 | + | |
117 | + updateRequestName : function(renamedNode) { | |
118 | + this.plotTabs.updateRequestName(renamedNode); | |
119 | + }, | |
120 | + | |
121 | + addTT : function(newTTName,newTTid,timeSelectorId) { | |
122 | + var crtTimeSelector = Ext.getCmp(timeSelectorId); | |
123 | + if (crtTimeSelector) | |
124 | + crtTimeSelector.addTT(newTTName,newTTid); | |
125 | + }, | |
126 | + | |
127 | + /** | |
128 | + * Set Start-Stop from parameter info (Local & MyData) | |
129 | + */ | |
130 | + setTimeFromData : function(obj) { | |
131 | + if (!obj.start || !obj.stop) | |
132 | + return; | |
133 | + var dateStart = new Date(obj.start.replace(/[T|Z]/g,' ').replace(/\-/g,'\/')); | |
134 | + var dateStop = new Date(obj.stop.replace(/[T|Z]/g,' ').replace(/\-/g,'\/')); | |
135 | + | |
136 | + var plotTab = this.plotTabs.getCurrentPlotTabContent(); | |
137 | + if (plotTab) | |
138 | + plotTab.setTime(dateStart, dateStop); | |
139 | + }, | |
140 | + | |
141 | + savePlotRequest : function() { | |
142 | + if (this.updateObject(true)) { | |
143 | + var plotTab = this.plotTabs.getCurrentPlotTabContent(); | |
144 | + if (plotTab) | |
145 | + plotTab.savePlot(); | |
146 | + } | |
147 | + }, | |
326 | 148 | |
327 | - init : function(config) { | |
328 | - this.timeSelector = new amdaUI.TimeSelectorUI( { id: 'multiPlotTimeSelector' + config.id, title : 'MultiPlot Time Selection', border : false, collapsible : true, collapseDirection : 'bottom', visible : false, flex: 2 } ); | |
329 | - | |
330 | - this.plotOutput = new amdaPlotComp.PlotOutputForm({flex: 2, collapseDirection : 'bottom', collapsible : true }); | |
331 | - | |
332 | - this.plotElement = new amdaPlotComp.PlotElementPanel({flex: 4}); | |
333 | - | |
334 | - this.plotTabs = new amdaPlotComp.PlotTabPanel({flex: 4, plotElementPanel : this.plotElement, plotUI : this}); | |
335 | - | |
336 | - this.optionsPanel = new Ext.form.Panel({ | |
337 | - layout: { | |
338 | - type: 'vbox', | |
339 | - pack: 'start', | |
340 | - align: 'stretch' | |
341 | - }, | |
342 | - bodyStyle: { background : '#dfe8f6' }, | |
343 | - defaults: { | |
344 | - border: false | |
345 | - }, | |
346 | - items: [ | |
347 | - this.plotElement, | |
348 | - this.plotOutput | |
349 | - ] | |
350 | - }); | |
351 | - | |
352 | - this.formPanel = new Ext.form.Panel({ | |
353 | - region: 'center', | |
354 | - layout: { | |
355 | - type: 'hbox', | |
356 | - pack: 'start', | |
357 | - align: 'stretch' | |
358 | - }, | |
359 | - bodyStyle: { background : '#dfe8f6' }, | |
360 | - defaults: { | |
361 | - border: false | |
362 | - }, | |
363 | - items: [ | |
364 | - { | |
365 | - xtype : 'panel', | |
366 | - layout: { | |
367 | - type: 'vbox', | |
368 | - pack: 'start', | |
369 | - align: 'stretch' | |
370 | - }, | |
371 | - bodyStyle: { background : '#dfe8f6' }, | |
372 | - defaults: { | |
373 | - border: false | |
374 | - }, | |
375 | - flex: 1, | |
376 | - items: [ | |
377 | - this.plotTabs, | |
378 | - this.timeSelector // this.multiPlotIntervalPanel | |
379 | - ] | |
380 | - }, | |
381 | - { | |
382 | - xtype : 'panel', | |
383 | - layout: 'fit', | |
384 | - bodyStyle: { background : '#dfe8f6' }, | |
385 | - defaults: { | |
386 | - border: false | |
387 | - }, | |
388 | - flex: 1, | |
389 | - items: [ | |
390 | - this.optionsPanel | |
391 | - ] | |
392 | - } | |
393 | - ], | |
394 | - fbar: [ | |
395 | - { | |
396 | - xtype: 'button', | |
397 | - text: 'Plot', | |
398 | - scope: this, | |
399 | - handler: function(button) { | |
400 | - this.doPlot(); | |
401 | - } | |
402 | - },' ', { | |
403 | - xtype: 'button', | |
404 | - text: 'Get Data', | |
405 | - scope: this, | |
406 | - handler: function(button) { | |
407 | - this.getDataProcess(); | |
408 | - } | |
409 | - },' ', { | |
410 | - xtype: 'button', | |
411 | - text: 'Reset', | |
412 | - scope: this, | |
413 | - handler: function(button) { | |
414 | - this.resetProcess(); | |
415 | - } | |
416 | - }, | |
417 | - '->', '-', { | |
418 | - xtype: 'splitbutton', | |
419 | - text: 'Save All Tabs', | |
420 | - menu: { | |
421 | - items: [ | |
422 | - { | |
423 | - text: 'Save Current Tab', | |
424 | - scope: this, | |
425 | - handler: function() { | |
426 | - this.savePlotRequest(false); | |
427 | - } | |
428 | - }, | |
429 | - ] | |
430 | - }, | |
431 | - scope: this, | |
432 | - handler: function(button) { | |
433 | - this.savePlotRequest(true); | |
434 | - } | |
435 | - } | |
436 | - ] | |
437 | - }); | |
438 | - | |
439 | - var myConf = { | |
440 | - layout: 'border', | |
441 | - items: [ | |
442 | - this.formPanel, | |
443 | - { | |
444 | - xtype: 'panel', | |
445 | - region: 'south', | |
446 | - title: 'Information', | |
447 | - collapsible: true, | |
448 | - collapseMode: 'header', | |
449 | - height: 100, | |
450 | - autoHide: false, | |
451 | - bodyStyle: 'padding:5px', | |
452 | - iconCls: 'icon-information', | |
453 | - loader: { | |
454 | - autoLoad: true, | |
455 | - url: helpDir+'plotHOWTO' | |
456 | - } | |
457 | - } | |
458 | - ] | |
459 | - }; | |
460 | - | |
461 | - Ext.apply(this, Ext.apply(arguments, myConf)); | |
462 | - } | |
149 | + init : function(config) { | |
150 | + this.plotTabs = new amdaPlotComp.PlotTabPanel({plotUI : this}); | |
151 | + | |
152 | + this.formPanel = new Ext.form.Panel({ | |
153 | + region: 'center', | |
154 | + layout: 'fit', | |
155 | + bodyStyle: { background : '#dfe8f6' }, | |
156 | + defaults: { | |
157 | + border: false | |
158 | + }, | |
159 | + items: [ | |
160 | + this.plotTabs | |
161 | + ], | |
162 | + fbar: [ | |
163 | + { | |
164 | + xtype: 'button', | |
165 | + text: 'Plot', | |
166 | + scope: this, | |
167 | + handler: function(button) { | |
168 | + this.doPlot(); | |
169 | + } | |
170 | + },' ', { | |
171 | + xtype: 'button', | |
172 | + text: 'Get Data', | |
173 | + scope: this, | |
174 | + handler: function(button) { | |
175 | + this.getDataProcess(); | |
176 | + } | |
177 | + },' ', { | |
178 | + xtype: 'button', | |
179 | + text: 'Reset', | |
180 | + scope: this, | |
181 | + handler: function(button) { | |
182 | + this.resetProcess(); | |
183 | + } | |
184 | + },'->', '-', { | |
185 | + xtype: 'button', | |
186 | + text: 'Save', | |
187 | + scope: this, | |
188 | + handler: function(button) { | |
189 | + this.savePlotRequest(); | |
190 | + } | |
191 | + } | |
192 | + ] | |
193 | + }); | |
194 | + | |
195 | + var myConf = { | |
196 | + layout: 'border', | |
197 | + items: [ | |
198 | + this.formPanel, | |
199 | + { | |
200 | + xtype: 'panel', | |
201 | + region: 'south', | |
202 | + title: 'Information', | |
203 | + collapsible: true, | |
204 | + collapseMode: 'header', | |
205 | + height: 100, | |
206 | + autoHide: false, | |
207 | + bodyStyle: 'padding:5px', | |
208 | + iconCls: 'icon-information', | |
209 | + loader: { | |
210 | + autoLoad: true, | |
211 | + url: helpDir+'plotHOWTO' | |
212 | + } | |
213 | + } | |
214 | + ] | |
215 | + }; | |
216 | + | |
217 | + Ext.apply(this, Ext.apply(arguments, myConf)); | |
218 | + } | |
463 | 219 | }); |
... | ... |
js/app/views/TimeSelectorUI.js
... | ... | @@ -61,6 +61,20 @@ Ext.define('amdaUI.TimeSelectorUI', { |
61 | 61 | getActiveTimeSource: function() { |
62 | 62 | return this.timeSrc.getActiveTab().getItemId(); |
63 | 63 | }, |
64 | + | |
65 | + isValid: function(acceptEmptyTTList = true) { | |
66 | + if (this.getActiveTimeSource() === amdaModel.AmdaTimeObject.inputTimeSrc[0]) { | |
67 | + //TimeTables | |
68 | + if (acceptEmptyTTList) | |
69 | + return true; | |
70 | + return (this.TTGrid.getStore().count() > 0); | |
71 | + } | |
72 | + else { | |
73 | + //Interval | |
74 | + return this.intervalSel.isValid(); | |
75 | + } | |
76 | + return true; | |
77 | + }, | |
64 | 78 | |
65 | 79 | initComponent: function() { |
66 | 80 | this.activeField = null; |
... | ... |
js/resources/css/AccueilAmda.css
... | ... | @@ -192,7 +192,6 @@ body{ |
192 | 192 | font-family: orbitronbold; |
193 | 193 | font-size: 16px; |
194 | 194 | color: rgba(0, 107, 179, 0.7); |
195 | - font-weight: bold; | |
196 | 195 | } |
197 | 196 | #userLogin { |
198 | 197 | position: relative; |
... | ... | @@ -217,7 +216,6 @@ body{ |
217 | 216 | font-family: orbitronbold; |
218 | 217 | font-size: 16px; |
219 | 218 | color: rgba(0, 107, 179, 0.9); |
220 | - font-weight: bold; | |
221 | 219 | } |
222 | 220 | /* โขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโข ANNOUCEMENTSโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโขโข*/ |
223 | 221 | #textAbout { |
... | ... |
js/resources/css/amda.css
... | ... | @@ -462,10 +462,6 @@ p + p { |
462 | 462 | background-image:url( ../images/16x16/plot_page.png ) !important; |
463 | 463 | } |
464 | 464 | |
465 | -.icon-plot-pages { | |
466 | - background-image:url( ../images/16x16/plot_pages.png ) !important; | |
467 | -} | |
468 | - | |
469 | 465 | .icon-plot-layout { |
470 | 466 | background-image:url( ../images/16x16/plot_layout.png ) !important; |
471 | 467 | } |
... | ... |
js/resources/images/16x16/plot_pages.png deleted
150 Bytes
php/classes/AmdaAction.php
... | ... | @@ -151,7 +151,6 @@ class AmdaAction |
151 | 151 | $isParameter = false; |
152 | 152 | $isAddable = false; |
153 | 153 | $isSimulation = false; |
154 | - $plotTabs = FALSE; | |
155 | 154 | $rank = null; |
156 | 155 | $skip = FALSE; |
157 | 156 | |
... | ... | @@ -185,19 +184,6 @@ class AmdaAction |
185 | 184 | else { |
186 | 185 | $info = $id; |
187 | 186 | } |
188 | - | |
189 | - $isLeaf = isset($objplot->tabs); | |
190 | - if ($isLeaf) { | |
191 | - $plotTabs = array(); | |
192 | - foreach ($objplot->tabs as $index => $tab) { | |
193 | - $plotTabs[$index] = array( | |
194 | - "name" => (!empty($tab->{'tab-name'})) ? $tab->{'tab-name'} : "Plot ".($index+1), | |
195 | - "id" => $tab->id, | |
196 | - ); | |
197 | - } | |
198 | - } | |
199 | - else | |
200 | - $plotTabs = FALSE; | |
201 | 187 | break; |
202 | 188 | |
203 | 189 | // case 'alias': |
... | ... | @@ -597,7 +583,7 @@ class AmdaAction |
597 | 583 | } |
598 | 584 | |
599 | 585 | $childrenToReturn[] = array('text' => $name, 'id' => $id, 'nodeType' => $nodeType, 'info' => $info, |
600 | - 'help' => $help, 'leaf' => $isLeaf, 'isParameter' => $isParameter, 'dim_1' => $dim_1, 'dim_2' => $dim_2, 'tabs' => $plotTabs, | |
586 | + 'help' => $help, 'leaf' => $isLeaf, 'isParameter' => $isParameter, 'dim_1' => $dim_1, 'dim_2' => $dim_2, | |
601 | 587 | 'component_info' => isset($component_info) ? $component_info : NULL, |
602 | 588 | 'iconCls' => isset($iconCls) ? $iconCls : NULL ); |
603 | 589 | } |
... | ... | @@ -826,7 +812,6 @@ class AmdaAction |
826 | 812 | break; |
827 | 813 | case 'condition' : |
828 | 814 | case 'request' : |
829 | - case 'plottab' : | |
830 | 815 | $objectMgr = new RequestMgr($obj->nodeType); |
831 | 816 | break; |
832 | 817 | case 'alias' : |
... | ... | @@ -916,7 +901,6 @@ class AmdaAction |
916 | 901 | break; |
917 | 902 | case 'condition' : |
918 | 903 | case 'request' : |
919 | - case 'plottab' : | |
920 | 904 | $objectMgr = new RequestMgr($obj->nodeType); |
921 | 905 | break; |
922 | 906 | default: |
... | ... | @@ -1437,11 +1421,10 @@ class AmdaAction |
1437 | 1421 | return array('success' => true); |
1438 | 1422 | } |
1439 | 1423 | |
1440 | - public function interactivePlot($obj, $multiPlotState) | |
1424 | + public function interactivePlot($obj) | |
1441 | 1425 | { |
1442 | 1426 | $inputobj = (Object)array( |
1443 | 1427 | 'action' => $obj, |
1444 | - 'multiPlotState' => $multiPlotState | |
1445 | 1428 | ); |
1446 | 1429 | return $this->executeRequest($inputobj, FunctionTypeEnumClass::ACTION); |
1447 | 1430 | } |
... | ... |
php/classes/RequestMgr.php
... | ... | @@ -30,7 +30,7 @@ class RequestMgr extends AmdaObjectMgr |
30 | 30 | $this->attributes = array('name' => ''); |
31 | 31 | $this->optionalAttributes = array(); |
32 | 32 | |
33 | - if ($type == 'request' || $type == 'plottab') | |
33 | + if ($type == 'request' ) | |
34 | 34 | { |
35 | 35 | $this->id_prefix = 'req_'; |
36 | 36 | } |
... | ... | @@ -73,47 +73,11 @@ class RequestMgr extends AmdaObjectMgr |
73 | 73 | |
74 | 74 | public function validNameObject($p) |
75 | 75 | { |
76 | - if ($this->type == 'plottab') { | |
77 | - if (empty($p->name)) { | |
78 | - return array('valid' => false, 'error' => 'Name is required'); | |
79 | - } | |
80 | - return array('valid' => true); | |
81 | - } | |
82 | 76 | return parent::validNameObject($p); |
83 | 77 | } |
84 | 78 | |
85 | 79 | public function renameObject($p) |
86 | 80 | { |
87 | - if ($this->type == 'plottab') { | |
88 | - //Rename a plot tab | |
89 | - if (!isset($p->parent) || empty($p->parent)) { | |
90 | - return array('error' => 'Missing parent definition'); | |
91 | - } | |
92 | - $plotObj = $this->getObject($p->parent); | |
93 | - if (is_array($plotObj) && isset($plotObj['error'])) { | |
94 | - return array('error' => $plotObj['error']); | |
95 | - } | |
96 | - if (!isset($plotObj->tabs)) { | |
97 | - return array('error' => 'Cannot retrieve tab in plot request'); | |
98 | - } | |
99 | - $renameOK = FALSE; | |
100 | - foreach ($plotObj->tabs as &$tab) { | |
101 | - if ($tab->id == $p->id) { | |
102 | - $tab->{'tab-name'} = $p->name; | |
103 | - $renameOK = TRUE; | |
104 | - break; | |
105 | - } | |
106 | - } | |
107 | - if (!$renameOK) { | |
108 | - return array('error' => 'Cannot retrieve tab in plot request 2'); | |
109 | - } | |
110 | - //Save modification | |
111 | - $file = fopen(USERREQDIR.$p->parent, 'w'); | |
112 | - fwrite($file, json_encode($plotObj)); | |
113 | - fclose($file); | |
114 | - | |
115 | - return array('id' => $p->id); | |
116 | - } | |
117 | 81 | return parent::renameObject($p); |
118 | 82 | } |
119 | 83 | |
... | ... | @@ -225,17 +189,6 @@ class RequestMgr extends AmdaObjectMgr |
225 | 189 | } |
226 | 190 | |
227 | 191 | $additional = array(); |
228 | - if ($this->type == 'request') { | |
229 | - $additional['tabs'] = array(); | |
230 | - if (isset($p->tabs)) { | |
231 | - foreach ($p->tabs as $index => $tab) { | |
232 | - $additional['tabs'][$index] = array( | |
233 | - "name" => (!empty($tab->{'tab-name'})) ? $tab->{'tab-name'} : "Plot ".($index+1), | |
234 | - "id" => $tab->id, | |
235 | - ); | |
236 | - } | |
237 | - } | |
238 | - } | |
239 | 192 | |
240 | 193 | $this->descFileName = USERREQDIR.$this->id; |
241 | 194 | $p->id = $this->id; |
... | ... | @@ -258,17 +211,12 @@ class RequestMgr extends AmdaObjectMgr |
258 | 211 | switch ($obj->nodeType) |
259 | 212 | { |
260 | 213 | case 'request' : |
261 | - foreach ($obj->tabs as $tab) | |
262 | - { | |
263 | - $timesrc = $tab->{'multi-plot-linked'} ? $obj->timesrc : $tab->timesrc; | |
264 | - | |
214 | + | |
265 | 215 | //TODO check TT as well (first start and last stop ?) |
266 | - if ($timesrc != 'Interval') continue; | |
267 | - // select active tab | |
268 | - if (!$tab->{'multi-plot-linked'} && $tab->id != $obj->{'last-plotted-tab'}) continue; | |
216 | + if ($obj->timesrc != 'Interval') continue; | |
269 | 217 | |
270 | 218 | $argsTab = array(); |
271 | - foreach ($tab->panels as $panel) | |
219 | + foreach ($obj->panels as $panel) | |
272 | 220 | { |
273 | 221 | $params = array(); |
274 | 222 | foreach ($panel->params as $param) |
... | ... | @@ -283,12 +231,11 @@ class RequestMgr extends AmdaObjectMgr |
283 | 231 | if (count($params) > 0) |
284 | 232 | { |
285 | 233 | $argsTab['param'] = array_unique($params); |
286 | - $argsTab['startTime'] = $tab->{'multi-plot-linked'} ? $obj->startDate : $tab->startDate; | |
287 | - $argsTab['stopTime'] = $tab->{'multi-plot-linked'} ? $obj->stopDate : $tab->stopDate; | |
234 | + $argsTab['startTime'] = $obj->startDate; | |
235 | + $argsTab['stopTime'] = $$obj->stopDate; | |
288 | 236 | } |
289 | 237 | } |
290 | 238 | if (count($argsTab) > 0) $args[] = $argsTab; |
291 | - } | |
292 | 239 | break; |
293 | 240 | case 'condition' : |
294 | 241 | //$argsTab = array(); |
... | ... |
php/classes/UserMgr.php
... | ... | @@ -517,6 +517,13 @@ class UserMgr |
517 | 517 | $this->isFirst = true; |
518 | 518 | } |
519 | 519 | |
520 | + $requestManager = new RequestManagerClass(); | |
521 | + try { | |
522 | + $res = $requestManager->runIHMRequest($this->user, $this->getIPclient(), FunctionTypeEnumClass::USERWSINIT, array()); | |
523 | + } catch (Exception $e) { | |
524 | + die("Login for ".$this->user." failed: Error in WS dirs - ".$e->getMessage()); | |
525 | + } | |
526 | + | |
520 | 527 | if (file_exists($this->userdir.'newLogin')) { |
521 | 528 | touch($this->userdir.'lastLogin', filemtime($this->userdir.'newLogin')); |
522 | 529 | } |
... | ... |
php/classes/simple_html_dom.php
1 | -<?php | |
2 | -/******************************************************************************* | |
3 | -Version: 1.11 ($Rev: 175 $) | |
4 | -Website: http://sourceforge.net/projects/simplehtmldom/ | |
5 | -Author: S.C. Chen <me578022@gmail.com> | |
6 | -Acknowledge: Jose Solorzano (https://sourceforge.net/projects/php-html/) | |
7 | -Contributions by: | |
8 | - Yousuke Kumakura (Attribute filters) | |
9 | - Vadim Voituk (Negative indexes supports of "find" method) | |
10 | - Antcs (Constructor with automatically load contents either text or file/url) | |
11 | -Licensed under The MIT License | |
12 | -Redistributions of files must retain the above copyright notice. | |
13 | -*******************************************************************************/ | |
14 | - | |
15 | -define('HDOM_TYPE_ELEMENT', 1); | |
16 | -define('HDOM_TYPE_COMMENT', 2); | |
17 | -define('HDOM_TYPE_TEXT', 3); | |
18 | -define('HDOM_TYPE_ENDTAG', 4); | |
19 | -define('HDOM_TYPE_ROOT', 5); | |
20 | -define('HDOM_TYPE_UNKNOWN', 6); | |
21 | -define('HDOM_QUOTE_DOUBLE', 0); | |
22 | -define('HDOM_QUOTE_SINGLE', 1); | |
23 | -define('HDOM_QUOTE_NO', 3); | |
24 | -define('HDOM_INFO_BEGIN', 0); | |
25 | -define('HDOM_INFO_END', 1); | |
26 | -define('HDOM_INFO_QUOTE', 2); | |
27 | -define('HDOM_INFO_SPACE', 3); | |
28 | -define('HDOM_INFO_TEXT', 4); | |
29 | -define('HDOM_INFO_INNER', 5); | |
30 | -define('HDOM_INFO_OUTER', 6); | |
31 | -define('HDOM_INFO_ENDSPACE',7); | |
32 | - | |
33 | -// helper functions | |
34 | -// ----------------------------------------------------------------------------- | |
35 | -// get html dom form file | |
36 | -function file_get_html() { | |
37 | - $dom = new simple_html_dom; | |
38 | - $args = func_get_args(); | |
39 | - $dom->load(call_user_func_array('file_get_contents', $args), true); | |
40 | - return $dom; | |
41 | -} | |
42 | - | |
43 | -// get html dom form string | |
44 | -function str_get_html($str, $lowercase=true) { | |
45 | - $dom = new simple_html_dom; | |
46 | - $dom->load($str, $lowercase); | |
47 | - return $dom; | |
48 | -} | |
49 | - | |
50 | -// dump html dom tree | |
51 | -function dump_html_tree($node, $show_attr=true, $deep=0) { | |
52 | - $lead = str_repeat(' ', $deep); | |
53 | - echo $lead.$node->tag; | |
54 | - if ($show_attr && count($node->attr)>0) { | |
55 | - echo '('; | |
56 | - foreach($node->attr as $k=>$v) | |
57 | - echo "[$k]=>\"".$node->$k.'", '; | |
58 | - echo ')'; | |
59 | - } | |
60 | - echo "\n"; | |
61 | - | |
62 | - foreach($node->nodes as $c) | |
63 | - dump_html_tree($c, $show_attr, $deep+1); | |
64 | -} | |
65 | - | |
66 | -// get dom form file (deprecated) | |
67 | -function file_get_dom() { | |
68 | - $dom = new simple_html_dom; | |
69 | - $args = func_get_args(); | |
70 | - $dom->load(call_user_func_array('file_get_contents', $args), true); | |
71 | - return $dom; | |
72 | -} | |
73 | - | |
74 | -// get dom form string (deprecated) | |
75 | -function str_get_dom($str, $lowercase=true) { | |
76 | - $dom = new simple_html_dom; | |
77 | - $dom->load($str, $lowercase); | |
78 | - return $dom; | |
79 | -} | |
80 | - | |
81 | -// simple html dom node | |
82 | -// ----------------------------------------------------------------------------- | |
83 | -class simple_html_dom_node { | |
84 | - public $nodetype = HDOM_TYPE_TEXT; | |
85 | - public $tag = 'text'; | |
86 | - public $attr = array(); | |
87 | - public $children = array(); | |
88 | - public $nodes = array(); | |
89 | - public $parent = null; | |
90 | - public $_ = array(); | |
91 | - private $dom = null; | |
92 | - | |
93 | - function __construct($dom) { | |
94 | - $this->dom = $dom; | |
95 | - $dom->nodes[] = $this; | |
96 | - } | |
97 | - | |
98 | - function __destruct() { | |
99 | - $this->clear(); | |
100 | - } | |
101 | - | |
102 | - function __toString() { | |
103 | - return $this->outertext(); | |
104 | - } | |
105 | - | |
106 | - // clean up memory due to php5 circular references memory leak... | |
107 | - function clear() { | |
108 | - $this->dom = null; | |
109 | - $this->nodes = null; | |
110 | - $this->parent = null; | |
111 | - $this->children = null; | |
112 | - } | |
113 | - | |
114 | - // dump node's tree | |
115 | - function dump($show_attr=true) { | |
116 | - dump_html_tree($this, $show_attr); | |
117 | - } | |
118 | - | |
119 | - // returns the parent of node | |
120 | - function parent() { | |
121 | - return $this->parent; | |
122 | - } | |
123 | - | |
124 | - // returns children of node | |
125 | - function children($idx=-1) { | |
126 | - if ($idx===-1) return $this->children; | |
127 | - if (isset($this->children[$idx])) return $this->children[$idx]; | |
128 | - return null; | |
129 | - } | |
130 | - | |
131 | - // returns the first child of node | |
132 | - function first_child() { | |
133 | - if (count($this->children)>0) return $this->children[0]; | |
134 | - return null; | |
135 | - } | |
136 | - | |
137 | - // returns the last child of node | |
138 | - function last_child() { | |
139 | - if (($count=count($this->children))>0) return $this->children[$count-1]; | |
140 | - return null; | |
141 | - } | |
142 | - | |
143 | - // returns the next sibling of node | |
144 | - function next_sibling() { | |
145 | - if ($this->parent===null) return null; | |
146 | - $idx = 0; | |
147 | - $count = count($this->parent->children); | |
148 | - while ($idx<$count && $this!==$this->parent->children[$idx]) | |
149 | - ++$idx; | |
150 | - if (++$idx>=$count) return null; | |
151 | - return $this->parent->children[$idx]; | |
152 | - } | |
153 | - | |
154 | - // returns the previous sibling of node | |
155 | - function prev_sibling() { | |
156 | - if ($this->parent===null) return null; | |
157 | - $idx = 0; | |
158 | - $count = count($this->parent->children); | |
159 | - while ($idx<$count && $this!==$this->parent->children[$idx]) | |
160 | - ++$idx; | |
161 | - if (--$idx<0) return null; | |
162 | - return $this->parent->children[$idx]; | |
163 | - } | |
164 | - | |
165 | - // get dom node's inner html | |
166 | - function innertext() { | |
167 | - if (isset($this->_[HDOM_INFO_INNER])) return $this->_[HDOM_INFO_INNER]; | |
168 | - if (isset($this->_[HDOM_INFO_TEXT])) return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]); | |
169 | - | |
170 | - $ret = ''; | |
171 | - foreach($this->nodes as $n) | |
172 | - $ret .= $n->outertext(); | |
173 | - return $ret; | |
174 | - } | |
175 | - | |
176 | - // get dom node's outer text (with tag) | |
177 | - function outertext() { | |
178 | - if ($this->tag==='root') return $this->innertext(); | |
179 | - | |
180 | - // trigger callback | |
181 | - if ($this->dom->callback!==null) | |
182 | - call_user_func_array($this->dom->callback, array($this)); | |
183 | - | |
184 | - if (isset($this->_[HDOM_INFO_OUTER])) return $this->_[HDOM_INFO_OUTER]; | |
185 | - if (isset($this->_[HDOM_INFO_TEXT])) return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]); | |
186 | - | |
187 | - // render begin tag | |
188 | - $ret = $this->dom->nodes[$this->_[HDOM_INFO_BEGIN]]->makeup(); | |
189 | - | |
190 | - // render inner text | |
191 | - if (isset($this->_[HDOM_INFO_INNER])) | |
192 | - $ret .= $this->_[HDOM_INFO_INNER]; | |
193 | - else { | |
194 | - foreach($this->nodes as $n) | |
195 | - $ret .= $n->outertext(); | |
196 | - } | |
197 | - | |
198 | - // render end tag | |
199 | - if(isset($this->_[HDOM_INFO_END]) && $this->_[HDOM_INFO_END]!=0) | |
200 | - $ret .= '</'.$this->tag.'>'; | |
201 | - return $ret; | |
202 | - } | |
203 | - | |
204 | - // get dom node's plain text | |
205 | - function text() { | |
206 | - if (isset($this->_[HDOM_INFO_INNER])) return $this->_[HDOM_INFO_INNER]; | |
207 | - switch ($this->nodetype) { | |
208 | - case HDOM_TYPE_TEXT: return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]); | |
209 | - case HDOM_TYPE_COMMENT: return ''; | |
210 | - case HDOM_TYPE_UNKNOWN: return ''; | |
211 | - } | |
212 | - if (strcasecmp($this->tag, 'script')===0) return ''; | |
213 | - if (strcasecmp($this->tag, 'style')===0) return ''; | |
214 | - | |
215 | - $ret = ''; | |
216 | - foreach($this->nodes as $n) | |
217 | - $ret .= $n->text(); | |
218 | - return $ret; | |
219 | - } | |
220 | - | |
221 | - function xmltext() { | |
222 | - $ret = $this->innertext(); | |
223 | - $ret = str_ireplace('<![CDATA[', '', $ret); | |
224 | - $ret = str_replace(']]>', '', $ret); | |
225 | - return $ret; | |
226 | - } | |
227 | - | |
228 | - // build node's text with tag | |
229 | - function makeup() { | |
230 | - // text, comment, unknown | |
231 | - if (isset($this->_[HDOM_INFO_TEXT])) return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]); | |
232 | - | |
233 | - $ret = '<'.$this->tag; | |
234 | - $i = -1; | |
235 | - | |
236 | - foreach($this->attr as $key=>$val) { | |
237 | - ++$i; | |
238 | - | |
239 | - // skip removed attribute | |
240 | - if ($val===null || $val===false) | |
241 | - continue; | |
242 | - | |
243 | - $ret .= $this->_[HDOM_INFO_SPACE][$i][0]; | |
244 | - //no value attr: nowrap, checked selected... | |
245 | - if ($val===true) | |
246 | - $ret .= $key; | |
247 | - else { | |
248 | - switch($this->_[HDOM_INFO_QUOTE][$i]) { | |
249 | - case HDOM_QUOTE_DOUBLE: $quote = '"'; break; | |
250 | - case HDOM_QUOTE_SINGLE: $quote = '\''; break; | |
251 | - default: $quote = ''; | |
252 | - } | |
253 | - $ret .= $key.$this->_[HDOM_INFO_SPACE][$i][1].'='.$this->_[HDOM_INFO_SPACE][$i][2].$quote.$val.$quote; | |
254 | - } | |
255 | - } | |
256 | - $ret = $this->dom->restore_noise($ret); | |
257 | - return $ret . $this->_[HDOM_INFO_ENDSPACE] . '>'; | |
258 | - } | |
259 | - | |
260 | - // find elements by css selector | |
261 | - function find($selector, $idx=null) { | |
262 | - $selectors = $this->parse_selector($selector); | |
263 | - if (($count=count($selectors))===0) return array(); | |
264 | - $found_keys = array(); | |
265 | - | |
266 | - // find each selector | |
267 | - for ($c=0; $c<$count; ++$c) { | |
268 | - if (($levle=count($selectors[0]))===0) return array(); | |
269 | - if (!isset($this->_[HDOM_INFO_BEGIN])) return array(); | |
270 | - | |
271 | - $head = array($this->_[HDOM_INFO_BEGIN]=>1); | |
272 | - | |
273 | - // handle descendant selectors, no recursive! | |
274 | - for ($l=0; $l<$levle; ++$l) { | |
275 | - $ret = array(); | |
276 | - foreach($head as $k=>$v) { | |
277 | - $n = ($k===-1) ? $this->dom->root : $this->dom->nodes[$k]; | |
278 | - $n->seek($selectors[$c][$l], $ret); | |
279 | - } | |
280 | - $head = $ret; | |
281 | - } | |
282 | - | |
283 | - foreach($head as $k=>$v) { | |
284 | - if (!isset($found_keys[$k])) | |
285 | - $found_keys[$k] = 1; | |
286 | - } | |
287 | - } | |
288 | - | |
289 | - // sort keys | |
290 | - ksort($found_keys); | |
291 | - | |
292 | - $found = array(); | |
293 | - foreach($found_keys as $k=>$v) | |
294 | - $found[] = $this->dom->nodes[$k]; | |
295 | - | |
296 | - // return nth-element or array | |
297 | - if (is_null($idx)) return $found; | |
298 | - else if ($idx<0) $idx = count($found) + $idx; | |
299 | - return (isset($found[$idx])) ? $found[$idx] : null; | |
300 | - } | |
301 | - | |
302 | - // seek for given conditions | |
303 | - protected function seek($selector, &$ret) { | |
304 | - list($tag, $key, $val, $exp, $no_key) = $selector; | |
305 | - | |
306 | - // xpath index | |
307 | - if ($tag && $key && is_numeric($key)) { | |
308 | - $count = 0; | |
309 | - foreach ($this->children as $c) { | |
310 | - if ($tag==='*' || $tag===$c->tag) { | |
311 | - if (++$count==$key) { | |
312 | - $ret[$c->_[HDOM_INFO_BEGIN]] = 1; | |
313 | - return; | |
314 | - } | |
315 | - } | |
316 | - } | |
317 | - return; | |
318 | - } | |
319 | - | |
320 | - $end = (!empty($this->_[HDOM_INFO_END])) ? $this->_[HDOM_INFO_END] : 0; | |
321 | - if ($end==0) { | |
322 | - $parent = $this->parent; | |
323 | - while (!isset($parent->_[HDOM_INFO_END]) && $parent!==null) { | |
324 | - $end -= 1; | |
325 | - $parent = $parent->parent; | |
326 | - } | |
327 | - $end += $parent->_[HDOM_INFO_END]; | |
328 | - } | |
329 | - | |
330 | - for($i=$this->_[HDOM_INFO_BEGIN]+1; $i<$end; ++$i) { | |
331 | - $node = $this->dom->nodes[$i]; | |
332 | - $pass = true; | |
333 | - | |
334 | - if ($tag==='*' && !$key) { | |
335 | - if (in_array($node, $this->children, true)) | |
336 | - $ret[$i] = 1; | |
337 | - continue; | |
338 | - } | |
339 | - | |
340 | - // compare tag | |
341 | - if ($tag && $tag!=$node->tag && $tag!=='*') {$pass=false;} | |
342 | - // compare key | |
343 | - if ($pass && $key) { | |
344 | - if ($no_key) { | |
345 | - if (isset($node->attr[$key])) $pass=false; | |
346 | - } | |
347 | - else if (!isset($node->attr[$key])) $pass=false; | |
348 | - } | |
349 | - // compare value | |
350 | - if ($pass && $key && $val && $val!=='*') { | |
351 | - $check = $this->match($exp, $val, $node->attr[$key]); | |
352 | - // handle multiple class | |
353 | - if (!$check && strcasecmp($key, 'class')===0) { | |
354 | - foreach(explode(' ',$node->attr[$key]) as $k) { | |
355 | - $check = $this->match($exp, $val, $k); | |
356 | - if ($check) break; | |
357 | - } | |
358 | - } | |
359 | - if (!$check) $pass = false; | |
360 | - } | |
361 | - if ($pass) $ret[$i] = 1; | |
362 | - unset($node); | |
363 | - } | |
364 | - } | |
365 | - | |
366 | - protected function match($exp, $pattern, $value) { | |
367 | - switch ($exp) { | |
368 | - case '=': | |
369 | - return ($value===$pattern); | |
370 | - case '!=': | |
371 | - return ($value!==$pattern); | |
372 | - case '^=': | |
373 | - return preg_match("/^".preg_quote($pattern,'/')."/", $value); | |
374 | - case '$=': | |
375 | - return preg_match("/".preg_quote($pattern,'/')."$/", $value); | |
376 | - case '*=': | |
377 | - if ($pattern[0]=='/') | |
378 | - return preg_match($pattern, $value); | |
379 | - return preg_match("/".$pattern."/i", $value); | |
380 | - } | |
381 | - return false; | |
382 | - } | |
383 | - | |
384 | - protected function parse_selector($selector_string) { | |
385 | - // pattern of CSS selectors, modified from mootools | |
386 | - $pattern = "/([\w-:\*]*)(?:\#([\w-]+)|\.([\w-]+))?(?:\[@?(!?[\w-]+)(?:([!*^$]?=)[\"']?(.*?)[\"']?)?\])?([\/, ]+)/is"; | |
387 | - preg_match_all($pattern, trim($selector_string).' ', $matches, PREG_SET_ORDER); | |
388 | - $selectors = array(); | |
389 | - $result = array(); | |
390 | - //print_r($matches); | |
391 | - | |
392 | - foreach ($matches as $m) { | |
393 | - $m[0] = trim($m[0]); | |
394 | - if ($m[0]==='' || $m[0]==='/' || $m[0]==='//') continue; | |
395 | - // for borwser grnreated xpath | |
396 | - if ($m[1]==='tbody') continue; | |
397 | - | |
398 | - list($tag, $key, $val, $exp, $no_key) = array($m[1], null, null, '=', false); | |
399 | - if(!empty($m[2])) {$key='id'; $val=$m[2];} | |
400 | - if(!empty($m[3])) {$key='class'; $val=$m[3];} | |
401 | - if(!empty($m[4])) {$key=$m[4];} | |
402 | - if(!empty($m[5])) {$exp=$m[5];} | |
403 | - if(!empty($m[6])) {$val=$m[6];} | |
404 | - | |
405 | - // convert to lowercase | |
406 | - if ($this->dom->lowercase) {$tag=strtolower($tag); $key=strtolower($key);} | |
407 | - //elements that do NOT have the specified attribute | |
408 | - if (isset($key[0]) && $key[0]==='!') {$key=substr($key, 1); $no_key=true;} | |
409 | - | |
410 | - $result[] = array($tag, $key, $val, $exp, $no_key); | |
411 | - if (trim($m[7])===',') { | |
412 | - $selectors[] = $result; | |
413 | - $result = array(); | |
414 | - } | |
415 | - } | |
416 | - if (count($result)>0) | |
417 | - $selectors[] = $result; | |
418 | - return $selectors; | |
419 | - } | |
420 | - | |
421 | - function __get($name) { | |
422 | - if (isset($this->attr[$name])) return $this->attr[$name]; | |
423 | - switch($name) { | |
424 | - case 'outertext': return $this->outertext(); | |
425 | - case 'innertext': return $this->innertext(); | |
426 | - case 'plaintext': return $this->text(); | |
427 | - case 'xmltext': return $this->xmltext(); | |
428 | - default: return array_key_exists($name, $this->attr); | |
429 | - } | |
430 | - } | |
431 | - | |
432 | - function __set($name, $value) { | |
433 | - switch($name) { | |
434 | - case 'outertext': return $this->_[HDOM_INFO_OUTER] = $value; | |
435 | - case 'innertext': | |
436 | - if (isset($this->_[HDOM_INFO_TEXT])) return $this->_[HDOM_INFO_TEXT] = $value; | |
437 | - return $this->_[HDOM_INFO_INNER] = $value; | |
438 | - } | |
439 | - if (!isset($this->attr[$name])) { | |
440 | - $this->_[HDOM_INFO_SPACE][] = array(' ', '', ''); | |
441 | - $this->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_DOUBLE; | |
442 | - } | |
443 | - $this->attr[$name] = $value; | |
444 | - } | |
445 | - | |
446 | - function __isset($name) { | |
447 | - switch($name) { | |
448 | - case 'outertext': return true; | |
449 | - case 'innertext': return true; | |
450 | - case 'plaintext': return true; | |
451 | - } | |
452 | - //no value attr: nowrap, checked selected... | |
453 | - return (array_key_exists($name, $this->attr)) ? true : isset($this->attr[$name]); | |
454 | - } | |
455 | - | |
456 | - function __unset($name) { | |
457 | - if (isset($this->attr[$name])) | |
458 | - unset($this->attr[$name]); | |
459 | - } | |
460 | - | |
461 | - // camel naming conventions | |
462 | - function getAllAttributes() {return $this->attr;} | |
463 | - function getAttribute($name) {return $this->__get($name);} | |
464 | - function setAttribute($name, $value) {$this->__set($name, $value);} | |
465 | - function hasAttribute($name) {return $this->__isset($name);} | |
466 | - function removeAttribute($name) {$this->__set($name, null);} | |
467 | - function getElementById($id) {return $this->find("#$id", 0);} | |
468 | - function getElementsById($id, $idx=null) {return $this->find("#$id", $idx);} | |
469 | - function getElementByTagName($name) {return $this->find($name, 0);} | |
470 | - function getElementsByTagName($name, $idx=null) {return $this->find($name, $idx);} | |
471 | - function parentNode() {return $this->parent();} | |
472 | - function childNodes($idx=-1) {return $this->children($idx);} | |
473 | - function firstChild() {return $this->first_child();} | |
474 | - function lastChild() {return $this->last_child();} | |
475 | - function nextSibling() {return $this->next_sibling();} | |
476 | - function previousSibling() {return $this->prev_sibling();} | |
477 | -} | |
478 | - | |
479 | -// simple html dom parser | |
480 | -// ----------------------------------------------------------------------------- | |
481 | -class simple_html_dom { | |
482 | - public $root = null; | |
483 | - public $nodes = array(); | |
484 | - public $callback = null; | |
485 | - public $lowercase = false; | |
486 | - protected $pos; | |
487 | - protected $doc; | |
488 | - protected $char; | |
489 | - protected $size; | |
490 | - protected $cursor; | |
491 | - protected $parent; | |
492 | - protected $noise = array(); | |
493 | - protected $token_blank = " \t\r\n"; | |
494 | - protected $token_equal = ' =/>'; | |
495 | - protected $token_slash = " />\r\n\t"; | |
496 | - protected $token_attr = ' >'; | |
497 | - // use isset instead of in_array, performance boost about 30%... | |
498 | - protected $self_closing_tags = array('img'=>1, 'br'=>1, 'input'=>1, 'meta'=>1, 'link'=>1, 'hr'=>1, 'base'=>1, 'embed'=>1, 'spacer'=>1); | |
499 | - protected $block_tags = array('root'=>1, 'body'=>1, 'form'=>1, 'div'=>1, 'span'=>1, 'table'=>1); | |
500 | - protected $optional_closing_tags = array( | |
501 | - 'tr'=>array('tr'=>1, 'td'=>1, 'th'=>1), | |
502 | - 'th'=>array('th'=>1), | |
503 | - 'td'=>array('td'=>1), | |
504 | - 'li'=>array('li'=>1), | |
505 | - 'dt'=>array('dt'=>1, 'dd'=>1), | |
506 | - 'dd'=>array('dd'=>1, 'dt'=>1), | |
507 | - 'dl'=>array('dd'=>1, 'dt'=>1), | |
508 | - 'p'=>array('p'=>1), | |
509 | - 'nobr'=>array('nobr'=>1), | |
510 | - ); | |
511 | - | |
512 | - function __construct($str=null) { | |
513 | - if ($str) { | |
514 | - if (preg_match("/^http:\/\//i",$str) || is_file($str)) | |
515 | - $this->load_file($str); | |
516 | - else | |
517 | - $this->load($str); | |
518 | - } | |
519 | - } | |
520 | - | |
521 | - function __destruct() { | |
522 | - $this->clear(); | |
523 | - } | |
524 | - | |
525 | - // load html from string | |
526 | - function load($str, $lowercase=true) { | |
527 | - // prepare | |
528 | - $this->prepare($str, $lowercase); | |
529 | - // strip out comments | |
530 | - $this->remove_noise("'<!--(.*?)-->'is"); | |
531 | - // strip out cdata | |
532 | - $this->remove_noise("'<!\[CDATA\[(.*?)\]\]>'is", true); | |
533 | - // strip out <style> tags | |
534 | - $this->remove_noise("'<\s*style[^>]*[^/]>(.*?)<\s*/\s*style\s*>'is"); | |
535 | - $this->remove_noise("'<\s*style\s*>(.*?)<\s*/\s*style\s*>'is"); | |
536 | - // strip out <script> tags | |
537 | - $this->remove_noise("'<\s*script[^>]*[^/]>(.*?)<\s*/\s*script\s*>'is"); | |
538 | - $this->remove_noise("'<\s*script\s*>(.*?)<\s*/\s*script\s*>'is"); | |
539 | - // strip out preformatted tags | |
540 | - $this->remove_noise("'<\s*(?:code)[^>]*>(.*?)<\s*/\s*(?:code)\s*>'is"); | |
541 | - // strip out server side scripts | |
542 | - $this->remove_noise("'(<\?)(.*?)(\?>)'s", true); | |
543 | - // strip smarty scripts | |
544 | - $this->remove_noise("'(\{\w)(.*?)(\})'s", true); | |
545 | - | |
546 | - // parsing | |
547 | - while ($this->parse()); | |
548 | - // end | |
549 | - $this->root->_[HDOM_INFO_END] = $this->cursor; | |
550 | - } | |
551 | - | |
552 | - // load html from file | |
553 | - function load_file() { | |
554 | - $args = func_get_args(); | |
555 | - $this->load(call_user_func_array('file_get_contents', $args), true); | |
556 | - } | |
557 | - | |
558 | - // set callback function | |
559 | - function set_callback($function_name) { | |
560 | - $this->callback = $function_name; | |
561 | - } | |
562 | - | |
563 | - // remove callback function | |
564 | - function remove_callback() { | |
565 | - $this->callback = null; | |
566 | - } | |
567 | - | |
568 | - // save dom as string | |
569 | - function save($filepath='') { | |
570 | - $ret = $this->root->innertext(); | |
571 | - if ($filepath!=='') file_put_contents($filepath, $ret); | |
572 | - return $ret; | |
573 | - } | |
574 | - | |
575 | - // find dom node by css selector | |
576 | - function find($selector, $idx=null) { | |
577 | - return $this->root->find($selector, $idx); | |
578 | - } | |
579 | - | |
580 | - // clean up memory due to php5 circular references memory leak... | |
581 | - function clear() { | |
582 | - foreach($this->nodes as $n) {$n->clear(); $n = null;} | |
583 | - if (isset($this->parent)) {$this->parent->clear(); unset($this->parent);} | |
584 | - if (isset($this->root)) {$this->root->clear(); unset($this->root);} | |
585 | - unset($this->doc); | |
586 | - unset($this->noise); | |
587 | - } | |
588 | - | |
589 | - function dump($show_attr=true) { | |
590 | - $this->root->dump($show_attr); | |
591 | - } | |
592 | - | |
593 | - // prepare HTML data and init everything | |
594 | - protected function prepare($str, $lowercase=true) { | |
595 | - $this->clear(); | |
596 | - $this->doc = $str; | |
597 | - $this->pos = 0; | |
598 | - $this->cursor = 1; | |
599 | - $this->noise = array(); | |
600 | - $this->nodes = array(); | |
601 | - $this->lowercase = $lowercase; | |
602 | - $this->root = new simple_html_dom_node($this); | |
603 | - $this->root->tag = 'root'; | |
604 | - $this->root->_[HDOM_INFO_BEGIN] = -1; | |
605 | - $this->root->nodetype = HDOM_TYPE_ROOT; | |
606 | - $this->parent = $this->root; | |
607 | - // set the length of content | |
608 | - $this->size = strlen($str); | |
609 | - if ($this->size>0) $this->char = $this->doc[0]; | |
610 | - } | |
611 | - | |
612 | - // parse html content | |
613 | - protected function parse() { | |
614 | - if (($s = $this->copy_until_char('<'))==='') | |
615 | - return $this->read_tag(); | |
616 | - | |
617 | - // text | |
618 | - $node = new simple_html_dom_node($this); | |
619 | - ++$this->cursor; | |
620 | - $node->_[HDOM_INFO_TEXT] = $s; | |
621 | - $this->link_nodes($node, false); | |
622 | - return true; | |
623 | - } | |
624 | - | |
625 | - // read tag info | |
626 | - protected function read_tag() { | |
627 | - if ($this->char!=='<') { | |
628 | - $this->root->_[HDOM_INFO_END] = $this->cursor; | |
629 | - return false; | |
630 | - } | |
631 | - $begin_tag_pos = $this->pos; | |
632 | - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next | |
633 | - | |
634 | - // end tag | |
635 | - if ($this->char==='/') { | |
636 | - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next | |
637 | - $this->skip($this->token_blank_t); | |
638 | - $tag = $this->copy_until_char('>'); | |
639 | - | |
640 | - // skip attributes in end tag | |
641 | - if (($pos = strpos($tag, ' '))!==false) | |
642 | - $tag = substr($tag, 0, $pos); | |
643 | - | |
644 | - $parent_lower = strtolower($this->parent->tag); | |
645 | - $tag_lower = strtolower($tag); | |
646 | - | |
647 | - if ($parent_lower!==$tag_lower) { | |
648 | - if (isset($this->optional_closing_tags[$parent_lower]) && isset($this->block_tags[$tag_lower])) { | |
649 | - $this->parent->_[HDOM_INFO_END] = 0; | |
650 | - $org_parent = $this->parent; | |
651 | - | |
652 | - while (($this->parent->parent) && strtolower($this->parent->tag)!==$tag_lower) | |
653 | - $this->parent = $this->parent->parent; | |
654 | - | |
655 | - if (strtolower($this->parent->tag)!==$tag_lower) { | |
656 | - $this->parent = $org_parent; // restore origonal parent | |
657 | - if ($this->parent->parent) $this->parent = $this->parent->parent; | |
658 | - $this->parent->_[HDOM_INFO_END] = $this->cursor; | |
659 | - return $this->as_text_node($tag); | |
660 | - } | |
661 | - } | |
662 | - else if (($this->parent->parent) && isset($this->block_tags[$tag_lower])) { | |
663 | - $this->parent->_[HDOM_INFO_END] = 0; | |
664 | - $org_parent = $this->parent; | |
665 | - | |
666 | - while (($this->parent->parent) && strtolower($this->parent->tag)!==$tag_lower) | |
667 | - $this->parent = $this->parent->parent; | |
668 | - | |
669 | - if (strtolower($this->parent->tag)!==$tag_lower) { | |
670 | - $this->parent = $org_parent; // restore origonal parent | |
671 | - $this->parent->_[HDOM_INFO_END] = $this->cursor; | |
672 | - return $this->as_text_node($tag); | |
673 | - } | |
674 | - } | |
675 | - else if (($this->parent->parent) && strtolower($this->parent->parent->tag)===$tag_lower) { | |
676 | - $this->parent->_[HDOM_INFO_END] = 0; | |
677 | - $this->parent = $this->parent->parent; | |
678 | - } | |
679 | - else | |
680 | - return $this->as_text_node($tag); | |
681 | - } | |
682 | - | |
683 | - $this->parent->_[HDOM_INFO_END] = $this->cursor; | |
684 | - if ($this->parent->parent) $this->parent = $this->parent->parent; | |
685 | - | |
686 | - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next | |
687 | - return true; | |
688 | - } | |
689 | - | |
690 | - $node = new simple_html_dom_node($this); | |
691 | - $node->_[HDOM_INFO_BEGIN] = $this->cursor; | |
692 | - ++$this->cursor; | |
693 | - $tag = $this->copy_until($this->token_slash); | |
694 | - | |
695 | - // doctype, cdata & comments... | |
696 | - if (isset($tag[0]) && $tag[0]==='!') { | |
697 | - $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until_char('>'); | |
698 | - | |
699 | - if (isset($tag[2]) && $tag[1]==='-' && $tag[2]==='-') { | |
700 | - $node->nodetype = HDOM_TYPE_COMMENT; | |
701 | - $node->tag = 'comment'; | |
702 | - } else { | |
703 | - $node->nodetype = HDOM_TYPE_UNKNOWN; | |
704 | - $node->tag = 'unknown'; | |
705 | - } | |
706 | - | |
707 | - if ($this->char==='>') $node->_[HDOM_INFO_TEXT].='>'; | |
708 | - $this->link_nodes($node, true); | |
709 | - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next | |
710 | - return true; | |
711 | - } | |
712 | - | |
713 | - // text | |
714 | - if ($pos=strpos($tag, '<')!==false) { | |
715 | - $tag = '<' . substr($tag, 0, -1); | |
716 | - $node->_[HDOM_INFO_TEXT] = $tag; | |
717 | - $this->link_nodes($node, false); | |
718 | - $this->char = $this->doc[--$this->pos]; // prev | |
719 | - return true; | |
720 | - } | |
721 | - | |
722 | - if (!preg_match("/^[\w-:]+$/", $tag)) { | |
723 | - $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until('<>'); | |
724 | - if ($this->char==='<') { | |
725 | - $this->link_nodes($node, false); | |
726 | - return true; | |
727 | - } | |
728 | - | |
729 | - if ($this->char==='>') $node->_[HDOM_INFO_TEXT].='>'; | |
730 | - $this->link_nodes($node, false); | |
731 | - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next | |
732 | - return true; | |
733 | - } | |
734 | - | |
735 | - // begin tag | |
736 | - $node->nodetype = HDOM_TYPE_ELEMENT; | |
737 | - $tag_lower = strtolower($tag); | |
738 | - $node->tag = ($this->lowercase) ? $tag_lower : $tag; | |
739 | - | |
740 | - // handle optional closing tags | |
741 | - if (isset($this->optional_closing_tags[$tag_lower]) ) { | |
742 | - while (isset($this->optional_closing_tags[$tag_lower][strtolower($this->parent->tag)])) { | |
743 | - $this->parent->_[HDOM_INFO_END] = 0; | |
744 | - $this->parent = $this->parent->parent; | |
745 | - } | |
746 | - $node->parent = $this->parent; | |
747 | - } | |
748 | - | |
749 | - $guard = 0; // prevent infinity loop | |
750 | - $space = array($this->copy_skip($this->token_blank), '', ''); | |
751 | - | |
752 | - // attributes | |
753 | - do { | |
754 | - if ($this->char!==null && $space[0]==='') break; | |
755 | - $name = $this->copy_until($this->token_equal); | |
756 | - if($guard===$this->pos) { | |
757 | - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next | |
758 | - continue; | |
759 | - } | |
760 | - $guard = $this->pos; | |
761 | - | |
762 | - // handle endless '<' | |
763 | - if($this->pos>=$this->size-1 && $this->char!=='>') { | |
764 | - $node->nodetype = HDOM_TYPE_TEXT; | |
765 | - $node->_[HDOM_INFO_END] = 0; | |
766 | - $node->_[HDOM_INFO_TEXT] = '<'.$tag . $space[0] . $name; | |
767 | - $node->tag = 'text'; | |
768 | - $this->link_nodes($node, false); | |
769 | - return true; | |
770 | - } | |
771 | - | |
772 | - // handle mismatch '<' | |
773 | - if($this->doc[$this->pos-1]=='<') { | |
774 | - $node->nodetype = HDOM_TYPE_TEXT; | |
775 | - $node->tag = 'text'; | |
776 | - $node->attr = array(); | |
777 | - $node->_[HDOM_INFO_END] = 0; | |
778 | - $node->_[HDOM_INFO_TEXT] = substr($this->doc, $begin_tag_pos, $this->pos-$begin_tag_pos-1); | |
779 | - $this->pos -= 2; | |
780 | - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next | |
781 | - $this->link_nodes($node, false); | |
782 | - return true; | |
783 | - } | |
784 | - | |
785 | - if ($name!=='/' && $name!=='') { | |
786 | - $space[1] = $this->copy_skip($this->token_blank); | |
787 | - $name = $this->restore_noise($name); | |
788 | - if ($this->lowercase) $name = strtolower($name); | |
789 | - if ($this->char==='=') { | |
790 | - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next | |
791 | - $this->parse_attr($node, $name, $space); | |
792 | - } | |
793 | - else { | |
794 | - //no value attr: nowrap, checked selected... | |
795 | - $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_NO; | |
796 | - $node->attr[$name] = true; | |
797 | - if ($this->char!='>') $this->char = $this->doc[--$this->pos]; // prev | |
798 | - } | |
799 | - $node->_[HDOM_INFO_SPACE][] = $space; | |
800 | - $space = array($this->copy_skip($this->token_blank), '', ''); | |
801 | - } | |
802 | - else | |
803 | - break; | |
804 | - } while($this->char!=='>' && $this->char!=='/'); | |
805 | - | |
806 | - $this->link_nodes($node, true); | |
807 | - $node->_[HDOM_INFO_ENDSPACE] = $space[0]; | |
808 | - | |
809 | - // check self closing | |
810 | - if ($this->copy_until_char_escape('>')==='/') { | |
811 | - $node->_[HDOM_INFO_ENDSPACE] .= '/'; | |
812 | - $node->_[HDOM_INFO_END] = 0; | |
813 | - } | |
814 | - else { | |
815 | - // reset parent | |
816 | - if (!isset($this->self_closing_tags[strtolower($node->tag)])) $this->parent = $node; | |
817 | - } | |
818 | - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next | |
819 | - return true; | |
820 | - } | |
821 | - | |
822 | - // parse attributes | |
823 | - protected function parse_attr($node, $name, &$space) { | |
824 | - $space[2] = $this->copy_skip($this->token_blank); | |
825 | - switch($this->char) { | |
826 | - case '"': | |
827 | - $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_DOUBLE; | |
828 | - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next | |
829 | - $node->attr[$name] = $this->restore_noise($this->copy_until_char_escape('"')); | |
830 | - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next | |
831 | - break; | |
832 | - case '\'': | |
833 | - $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_SINGLE; | |
834 | - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next | |
835 | - $node->attr[$name] = $this->restore_noise($this->copy_until_char_escape('\'')); | |
836 | - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next | |
837 | - break; | |
838 | - default: | |
839 | - $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_NO; | |
840 | - $node->attr[$name] = $this->restore_noise($this->copy_until($this->token_attr)); | |
841 | - } | |
842 | - } | |
843 | - | |
844 | - // link node's parent | |
845 | - protected function link_nodes(&$node, $is_child) { | |
846 | - $node->parent = $this->parent; | |
847 | - $this->parent->nodes[] = $node; | |
848 | - if ($is_child) | |
849 | - $this->parent->children[] = $node; | |
850 | - } | |
851 | - | |
852 | - // as a text node | |
853 | - protected function as_text_node($tag) { | |
854 | - $node = new simple_html_dom_node($this); | |
855 | - ++$this->cursor; | |
856 | - $node->_[HDOM_INFO_TEXT] = '</' . $tag . '>'; | |
857 | - $this->link_nodes($node, false); | |
858 | - $this->char = (++$this->pos<$this->size) ? $this->doc[$this->pos] : null; // next | |
859 | - return true; | |
860 | - } | |
861 | - | |
862 | - protected function skip($chars) { | |
863 | - $this->pos += strspn($this->doc, $chars, $this->pos); | |
864 | - $this->char = ($this->pos<$this->size) ? $this->doc[$this->pos] : null; // next | |
865 | - } | |
866 | - | |
867 | - protected function copy_skip($chars) { | |
868 | - $pos = $this->pos; | |
869 | - $len = strspn($this->doc, $chars, $pos); | |
870 | - $this->pos += $len; | |
871 | - $this->char = ($this->pos<$this->size) ? $this->doc[$this->pos] : null; // next | |
872 | - if ($len===0) return ''; | |
873 | - return substr($this->doc, $pos, $len); | |
874 | - } | |
875 | - | |
876 | - protected function copy_until($chars) { | |
877 | - $pos = $this->pos; | |
878 | - $len = strcspn($this->doc, $chars, $pos); | |
879 | - $this->pos += $len; | |
880 | - $this->char = ($this->pos<$this->size) ? $this->doc[$this->pos] : null; // next | |
881 | - return substr($this->doc, $pos, $len); | |
882 | - } | |
883 | - | |
884 | - protected function copy_until_char($char) { | |
885 | - if ($this->char===null) return ''; | |
886 | - | |
887 | - if (($pos = strpos($this->doc, $char, $this->pos))===false) { | |
888 | - $ret = substr($this->doc, $this->pos, $this->size-$this->pos); | |
889 | - $this->char = null; | |
890 | - $this->pos = $this->size; | |
891 | - return $ret; | |
892 | - } | |
893 | - | |
894 | - if ($pos===$this->pos) return ''; | |
895 | - $pos_old = $this->pos; | |
896 | - $this->char = $this->doc[$pos]; | |
897 | - $this->pos = $pos; | |
898 | - return substr($this->doc, $pos_old, $pos-$pos_old); | |
899 | - } | |
900 | - | |
901 | - protected function copy_until_char_escape($char) { | |
902 | - if ($this->char===null) return ''; | |
903 | - | |
904 | - $start = $this->pos; | |
905 | - while(1) { | |
906 | - if (($pos = strpos($this->doc, $char, $start))===false) { | |
907 | - $ret = substr($this->doc, $this->pos, $this->size-$this->pos); | |
908 | - $this->char = null; | |
909 | - $this->pos = $this->size; | |
910 | - return $ret; | |
911 | - } | |
912 | - | |
913 | - if ($pos===$this->pos) return ''; | |
914 | - | |
915 | - if ($this->doc[$pos-1]==='\\') { | |
916 | - $start = $pos+1; | |
917 | - continue; | |
918 | - } | |
919 | - | |
920 | - $pos_old = $this->pos; | |
921 | - $this->char = $this->doc[$pos]; | |
922 | - $this->pos = $pos; | |
923 | - return substr($this->doc, $pos_old, $pos-$pos_old); | |
924 | - } | |
925 | - } | |
926 | - | |
927 | - // remove noise from html content | |
928 | - protected function remove_noise($pattern, $remove_tag=false) { | |
929 | - $count = preg_match_all($pattern, $this->doc, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE); | |
930 | - | |
931 | - for ($i=$count-1; $i>-1; --$i) { | |
932 | - $key = '___noise___'.sprintf('% 3d', count($this->noise)+100); | |
933 | - $idx = ($remove_tag) ? 0 : 1; | |
934 | - $this->noise[$key] = $matches[$i][$idx][0]; | |
935 | - $this->doc = substr_replace($this->doc, $key, $matches[$i][$idx][1], strlen($matches[$i][$idx][0])); | |
936 | - } | |
937 | - | |
938 | - // reset the length of content | |
939 | - $this->size = strlen($this->doc); | |
940 | - if ($this->size>0) $this->char = $this->doc[0]; | |
941 | - } | |
942 | - | |
943 | - // restore noise to html content | |
944 | - function restore_noise($text) { | |
945 | - while(($pos=strpos($text, '___noise___'))!==false) { | |
946 | - $key = '___noise___'.$text[$pos+11].$text[$pos+12].$text[$pos+13]; | |
947 | - if (isset($this->noise[$key])) | |
948 | - $text = substr($text, 0, $pos).$this->noise[$key].substr($text, $pos+14); | |
949 | - } | |
950 | - return $text; | |
951 | - } | |
952 | - | |
953 | - function __toString() { | |
954 | - return $this->root->innertext(); | |
955 | - } | |
956 | - | |
957 | - function __get($name) { | |
958 | - switch($name) { | |
959 | - case 'outertext': return $this->root->innertext(); | |
960 | - case 'innertext': return $this->root->innertext(); | |
961 | - case 'plaintext': return $this->root->text(); | |
962 | - } | |
963 | - } | |
964 | - | |
965 | - // camel naming conventions | |
966 | - function childNodes($idx=-1) {return $this->root->childNodes($idx);} | |
967 | - function firstChild() {return $this->root->first_child();} | |
968 | - function lastChild() {return $this->root->last_child();} | |
969 | - function getElementById($id) {return $this->find("#$id", 0);} | |
970 | - function getElementsById($id, $idx=null) {return $this->find("#$id", $idx);} | |
971 | - function getElementByTagName($name) {return $this->find($name, 0);} | |
972 | - function getElementsByTagName($name, $idx=-1) {return $this->find($name, $idx);} | |
973 | - function loadFile() {$args = func_get_args();$this->load(call_user_func_array('file_get_contents', $args), true);} | |
974 | -} | |
975 | -?> | |
976 | 1 | \ No newline at end of file |
2 | +<?php | |
3 | +/** | |
4 | + * Website: http://sourceforge.net/projects/simplehtmldom/ | |
5 | + * Additional projects: http://sourceforge.net/projects/debugobject/ | |
6 | + * Acknowledge: Jose Solorzano (https://sourceforge.net/projects/php-html/) | |
7 | + * | |
8 | + * Licensed under The MIT License | |
9 | + * See the LICENSE file in the project root for more information. | |
10 | + * | |
11 | + * Authors: | |
12 | + * S.C. Chen | |
13 | + * John Schlick | |
14 | + * Rus Carroll | |
15 | + * logmanoriginal | |
16 | + * | |
17 | + * Contributors: | |
18 | + * Yousuke Kumakura | |
19 | + * Vadim Voituk | |
20 | + * Antcs | |
21 | + * | |
22 | + * Version Rev. 1.9 (290) | |
23 | + */ | |
24 | + | |
25 | +define('HDOM_TYPE_ELEMENT', 1); | |
26 | +define('HDOM_TYPE_COMMENT', 2); | |
27 | +define('HDOM_TYPE_TEXT', 3); | |
28 | +define('HDOM_TYPE_ENDTAG', 4); | |
29 | +define('HDOM_TYPE_ROOT', 5); | |
30 | +define('HDOM_TYPE_UNKNOWN', 6); | |
31 | +define('HDOM_QUOTE_DOUBLE', 0); | |
32 | +define('HDOM_QUOTE_SINGLE', 1); | |
33 | +define('HDOM_QUOTE_NO', 3); | |
34 | +define('HDOM_INFO_BEGIN', 0); | |
35 | +define('HDOM_INFO_END', 1); | |
36 | +define('HDOM_INFO_QUOTE', 2); | |
37 | +define('HDOM_INFO_SPACE', 3); | |
38 | +define('HDOM_INFO_TEXT', 4); | |
39 | +define('HDOM_INFO_INNER', 5); | |
40 | +define('HDOM_INFO_OUTER', 6); | |
41 | +define('HDOM_INFO_ENDSPACE', 7); | |
42 | + | |
43 | +defined('DEFAULT_TARGET_CHARSET') || define('DEFAULT_TARGET_CHARSET', 'UTF-8'); | |
44 | +defined('DEFAULT_BR_TEXT') || define('DEFAULT_BR_TEXT', "\r\n"); | |
45 | +defined('DEFAULT_SPAN_TEXT') || define('DEFAULT_SPAN_TEXT', ' '); | |
46 | +defined('MAX_FILE_SIZE') || define('MAX_FILE_SIZE', 600000); | |
47 | +define('HDOM_SMARTY_AS_TEXT', 1); | |
48 | + | |
49 | +function file_get_html( | |
50 | + $url, | |
51 | + $use_include_path = false, | |
52 | + $context = null, | |
53 | + $offset = 0, | |
54 | + $maxLen = -1, | |
55 | + $lowercase = true, | |
56 | + $forceTagsClosed = true, | |
57 | + $target_charset = DEFAULT_TARGET_CHARSET, | |
58 | + $stripRN = true, | |
59 | + $defaultBRText = DEFAULT_BR_TEXT, | |
60 | + $defaultSpanText = DEFAULT_SPAN_TEXT) | |
61 | +{ | |
62 | + if($maxLen <= 0) { $maxLen = MAX_FILE_SIZE; } | |
63 | + | |
64 | + $dom = new simple_html_dom( | |
65 | + null, | |
66 | + $lowercase, | |
67 | + $forceTagsClosed, | |
68 | + $target_charset, | |
69 | + $stripRN, | |
70 | + $defaultBRText, | |
71 | + $defaultSpanText | |
72 | + ); | |
73 | + | |
74 | + /** | |
75 | + * For sourceforge users: uncomment the next line and comment the | |
76 | + * retrieve_url_contents line 2 lines down if it is not already done. | |
77 | + */ | |
78 | + $contents = file_get_contents( | |
79 | + $url, | |
80 | + $use_include_path, | |
81 | + $context, | |
82 | + $offset, | |
83 | + $maxLen | |
84 | + ); | |
85 | + // $contents = retrieve_url_contents($url); | |
86 | + | |
87 | + if (empty($contents) || strlen($contents) > $maxLen) { | |
88 | + $dom->clear(); | |
89 | + return false; | |
90 | + } | |
91 | + | |
92 | + return $dom->load($contents, $lowercase, $stripRN); | |
93 | +} | |
94 | + | |
95 | +function str_get_html( | |
96 | + $str, | |
97 | + $lowercase = true, | |
98 | + $forceTagsClosed = true, | |
99 | + $target_charset = DEFAULT_TARGET_CHARSET, | |
100 | + $stripRN = true, | |
101 | + $defaultBRText = DEFAULT_BR_TEXT, | |
102 | + $defaultSpanText = DEFAULT_SPAN_TEXT) | |
103 | +{ | |
104 | + $dom = new simple_html_dom( | |
105 | + null, | |
106 | + $lowercase, | |
107 | + $forceTagsClosed, | |
108 | + $target_charset, | |
109 | + $stripRN, | |
110 | + $defaultBRText, | |
111 | + $defaultSpanText | |
112 | + ); | |
113 | + | |
114 | + if (empty($str) || strlen($str) > MAX_FILE_SIZE) { | |
115 | + $dom->clear(); | |
116 | + return false; | |
117 | + } | |
118 | + | |
119 | + return $dom->load($str, $lowercase, $stripRN); | |
120 | +} | |
121 | + | |
122 | +function dump_html_tree($node, $show_attr = true, $deep = 0) | |
123 | +{ | |
124 | + $node->dump($node); | |
125 | +} | |
126 | + | |
127 | +class simple_html_dom_node | |
128 | +{ | |
129 | + public $nodetype = HDOM_TYPE_TEXT; | |
130 | + public $tag = 'text'; | |
131 | + public $attr = array(); | |
132 | + public $children = array(); | |
133 | + public $nodes = array(); | |
134 | + public $parent = null; | |
135 | + public $_ = array(); | |
136 | + public $tag_start = 0; | |
137 | + private $dom = null; | |
138 | + | |
139 | + function __construct($dom) | |
140 | + { | |
141 | + $this->dom = $dom; | |
142 | + $dom->nodes[] = $this; | |
143 | + } | |
144 | + | |
145 | + function __destruct() | |
146 | + { | |
147 | + $this->clear(); | |
148 | + } | |
149 | + | |
150 | + function __toString() | |
151 | + { | |
152 | + return $this->outertext(); | |
153 | + } | |
154 | + | |
155 | + function clear() | |
156 | + { | |
157 | + $this->dom = null; | |
158 | + $this->nodes = null; | |
159 | + $this->parent = null; | |
160 | + $this->children = null; | |
161 | + } | |
162 | + | |
163 | + function dump($show_attr = true, $depth = 0) | |
164 | + { | |
165 | + echo str_repeat("\t", $depth) . $this->tag; | |
166 | + | |
167 | + if ($show_attr && count($this->attr) > 0) { | |
168 | + echo '('; | |
169 | + foreach ($this->attr as $k => $v) { | |
170 | + echo "[$k]=>\"$v\", "; | |
171 | + } | |
172 | + echo ')'; | |
173 | + } | |
174 | + | |
175 | + echo "\n"; | |
176 | + | |
177 | + if ($this->nodes) { | |
178 | + foreach ($this->nodes as $node) { | |
179 | + $node->dump($show_attr, $depth + 1); | |
180 | + } | |
181 | + } | |
182 | + } | |
183 | + | |
184 | + function dump_node($echo = true) | |
185 | + { | |
186 | + $string = $this->tag; | |
187 | + | |
188 | + if (count($this->attr) > 0) { | |
189 | + $string .= '('; | |
190 | + foreach ($this->attr as $k => $v) { | |
191 | + $string .= "[$k]=>\"$v\", "; | |
192 | + } | |
193 | + $string .= ')'; | |
194 | + } | |
195 | + | |
196 | + if (count($this->_) > 0) { | |
197 | + $string .= ' $_ ('; | |
198 | + foreach ($this->_ as $k => $v) { | |
199 | + if (is_array($v)) { | |
200 | + $string .= "[$k]=>("; | |
201 | + foreach ($v as $k2 => $v2) { | |
202 | + $string .= "[$k2]=>\"$v2\", "; | |
203 | + } | |
204 | + $string .= ')'; | |
205 | + } else { | |
206 | + $string .= "[$k]=>\"$v\", "; | |
207 | + } | |
208 | + } | |
209 | + $string .= ')'; | |
210 | + } | |
211 | + | |
212 | + if (isset($this->text)) { | |
213 | + $string .= " text: ({$this->text})"; | |
214 | + } | |
215 | + | |
216 | + $string .= ' HDOM_INNER_INFO: '; | |
217 | + | |
218 | + if (isset($node->_[HDOM_INFO_INNER])) { | |
219 | + $string .= "'" . $node->_[HDOM_INFO_INNER] . "'"; | |
220 | + } else { | |
221 | + $string .= ' NULL '; | |
222 | + } | |
223 | + | |
224 | + $string .= ' children: ' . count($this->children); | |
225 | + $string .= ' nodes: ' . count($this->nodes); | |
226 | + $string .= ' tag_start: ' . $this->tag_start; | |
227 | + $string .= "\n"; | |
228 | + | |
229 | + if ($echo) { | |
230 | + echo $string; | |
231 | + return; | |
232 | + } else { | |
233 | + return $string; | |
234 | + } | |
235 | + } | |
236 | + | |
237 | + function parent($parent = null) | |
238 | + { | |
239 | + // I am SURE that this doesn't work properly. | |
240 | + // It fails to unset the current node from it's current parents nodes or | |
241 | + // children list first. | |
242 | + if ($parent !== null) { | |
243 | + $this->parent = $parent; | |
244 | + $this->parent->nodes[] = $this; | |
245 | + $this->parent->children[] = $this; | |
246 | + } | |
247 | + | |
248 | + return $this->parent; | |
249 | + } | |
250 | + | |
251 | + function has_child() | |
252 | + { | |
253 | + return !empty($this->children); | |
254 | + } | |
255 | + | |
256 | + function children($idx = -1) | |
257 | + { | |
258 | + if ($idx === -1) { | |
259 | + return $this->children; | |
260 | + } | |
261 | + | |
262 | + if (isset($this->children[$idx])) { | |
263 | + return $this->children[$idx]; | |
264 | + } | |
265 | + | |
266 | + return null; | |
267 | + } | |
268 | + | |
269 | + function first_child() | |
270 | + { | |
271 | + if (count($this->children) > 0) { | |
272 | + return $this->children[0]; | |
273 | + } | |
274 | + return null; | |
275 | + } | |
276 | + | |
277 | + function last_child() | |
278 | + { | |
279 | + if (count($this->children) > 0) { | |
280 | + return end($this->children); | |
281 | + } | |
282 | + return null; | |
283 | + } | |
284 | + | |
285 | + function next_sibling() | |
286 | + { | |
287 | + if ($this->parent === null) { | |
288 | + return null; | |
289 | + } | |
290 | + | |
291 | + $idx = array_search($this, $this->parent->children, true); | |
292 | + | |
293 | + if ($idx !== false && isset($this->parent->children[$idx + 1])) { | |
294 | + return $this->parent->children[$idx + 1]; | |
295 | + } | |
296 | + | |
297 | + return null; | |
298 | + } | |
299 | + | |
300 | + function prev_sibling() | |
301 | + { | |
302 | + if ($this->parent === null) { | |
303 | + return null; | |
304 | + } | |
305 | + | |
306 | + $idx = array_search($this, $this->parent->children, true); | |
307 | + | |
308 | + if ($idx !== false && $idx > 0) { | |
309 | + return $this->parent->children[$idx - 1]; | |
310 | + } | |
311 | + | |
312 | + return null; | |
313 | + } | |
314 | + | |
315 | + function find_ancestor_tag($tag) | |
316 | + { | |
317 | + global $debug_object; | |
318 | + if (is_object($debug_object)) { $debug_object->debug_log_entry(1); } | |
319 | + | |
320 | + if ($this->parent === null) { | |
321 | + return null; | |
322 | + } | |
323 | + | |
324 | + $ancestor = $this->parent; | |
325 | + | |
326 | + while (!is_null($ancestor)) { | |
327 | + if (is_object($debug_object)) { | |
328 | + $debug_object->debug_log(2, 'Current tag is: ' . $ancestor->tag); | |
329 | + } | |
330 | + | |
331 | + if ($ancestor->tag === $tag) { | |
332 | + break; | |
333 | + } | |
334 | + | |
335 | + $ancestor = $ancestor->parent; | |
336 | + } | |
337 | + | |
338 | + return $ancestor; | |
339 | + } | |
340 | + | |
341 | + function innertext() | |
342 | + { | |
343 | + if (isset($this->_[HDOM_INFO_INNER])) { | |
344 | + return $this->_[HDOM_INFO_INNER]; | |
345 | + } | |
346 | + | |
347 | + if (isset($this->_[HDOM_INFO_TEXT])) { | |
348 | + return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]); | |
349 | + } | |
350 | + | |
351 | + $ret = ''; | |
352 | + | |
353 | + foreach ($this->nodes as $n) { | |
354 | + $ret .= $n->outertext(); | |
355 | + } | |
356 | + | |
357 | + return $ret; | |
358 | + } | |
359 | + | |
360 | + function outertext() | |
361 | + { | |
362 | + global $debug_object; | |
363 | + | |
364 | + if (is_object($debug_object)) { | |
365 | + $text = ''; | |
366 | + | |
367 | + if ($this->tag === 'text') { | |
368 | + if (!empty($this->text)) { | |
369 | + $text = ' with text: ' . $this->text; | |
370 | + } | |
371 | + } | |
372 | + | |
373 | + $debug_object->debug_log(1, 'Innertext of tag: ' . $this->tag . $text); | |
374 | + } | |
375 | + | |
376 | + if ($this->tag === 'root') { | |
377 | + return $this->innertext(); | |
378 | + } | |
379 | + | |
380 | + // todo: What is the use of this callback? Remove? | |
381 | + if ($this->dom && $this->dom->callback !== null) { | |
382 | + call_user_func_array($this->dom->callback, array($this)); | |
383 | + } | |
384 | + | |
385 | + if (isset($this->_[HDOM_INFO_OUTER])) { | |
386 | + return $this->_[HDOM_INFO_OUTER]; | |
387 | + } | |
388 | + | |
389 | + if (isset($this->_[HDOM_INFO_TEXT])) { | |
390 | + return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]); | |
391 | + } | |
392 | + | |
393 | + $ret = ''; | |
394 | + | |
395 | + if ($this->dom && $this->dom->nodes[$this->_[HDOM_INFO_BEGIN]]) { | |
396 | + $ret = $this->dom->nodes[$this->_[HDOM_INFO_BEGIN]]->makeup(); | |
397 | + } | |
398 | + | |
399 | + if (isset($this->_[HDOM_INFO_INNER])) { | |
400 | + // todo: <br> should either never have HDOM_INFO_INNER or always | |
401 | + if ($this->tag !== 'br') { | |
402 | + $ret .= $this->_[HDOM_INFO_INNER]; | |
403 | + } | |
404 | + } elseif ($this->nodes) { | |
405 | + foreach ($this->nodes as $n) { | |
406 | + $ret .= $this->convert_text($n->outertext()); | |
407 | + } | |
408 | + } | |
409 | + | |
410 | + if (isset($this->_[HDOM_INFO_END]) && $this->_[HDOM_INFO_END] != 0) { | |
411 | + $ret .= '</' . $this->tag . '>'; | |
412 | + } | |
413 | + | |
414 | + return $ret; | |
415 | + } | |
416 | + | |
417 | + function text() | |
418 | + { | |
419 | + if (isset($this->_[HDOM_INFO_INNER])) { | |
420 | + return $this->_[HDOM_INFO_INNER]; | |
421 | + } | |
422 | + | |
423 | + switch ($this->nodetype) { | |
424 | + case HDOM_TYPE_TEXT: return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]); | |
425 | + case HDOM_TYPE_COMMENT: return ''; | |
426 | + case HDOM_TYPE_UNKNOWN: return ''; | |
427 | + } | |
428 | + | |
429 | + if (strcasecmp($this->tag, 'script') === 0) { return ''; } | |
430 | + if (strcasecmp($this->tag, 'style') === 0) { return ''; } | |
431 | + | |
432 | + $ret = ''; | |
433 | + | |
434 | + // In rare cases, (always node type 1 or HDOM_TYPE_ELEMENT - observed | |
435 | + // for some span tags, and some p tags) $this->nodes is set to NULL. | |
436 | + // NOTE: This indicates that there is a problem where it's set to NULL | |
437 | + // without a clear happening. | |
438 | + // WHY is this happening? | |
439 | + if (!is_null($this->nodes)) { | |
440 | + foreach ($this->nodes as $n) { | |
441 | + // Start paragraph after a blank line | |
442 | + if ($n->tag === 'p') { | |
443 | + $ret = trim($ret) . "\n\n"; | |
444 | + } | |
445 | + | |
446 | + $ret .= $this->convert_text($n->text()); | |
447 | + | |
448 | + // If this node is a span... add a space at the end of it so | |
449 | + // multiple spans don't run into each other. This is plaintext | |
450 | + // after all. | |
451 | + if ($n->tag === 'span') { | |
452 | + $ret .= $this->dom->default_span_text; | |
453 | + } | |
454 | + } | |
455 | + } | |
456 | + return $ret; | |
457 | + } | |
458 | + | |
459 | + function xmltext() | |
460 | + { | |
461 | + $ret = $this->innertext(); | |
462 | + $ret = str_ireplace('<![CDATA[', '', $ret); | |
463 | + $ret = str_replace(']]>', '', $ret); | |
464 | + return $ret; | |
465 | + } | |
466 | + | |
467 | + function makeup() | |
468 | + { | |
469 | + // text, comment, unknown | |
470 | + if (isset($this->_[HDOM_INFO_TEXT])) { | |
471 | + return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]); | |
472 | + } | |
473 | + | |
474 | + $ret = '<' . $this->tag; | |
475 | + $i = -1; | |
476 | + | |
477 | + foreach ($this->attr as $key => $val) { | |
478 | + ++$i; | |
479 | + | |
480 | + // skip removed attribute | |
481 | + if ($val === null || $val === false) { continue; } | |
482 | + | |
483 | + $ret .= $this->_[HDOM_INFO_SPACE][$i][0]; | |
484 | + | |
485 | + //no value attr: nowrap, checked selected... | |
486 | + if ($val === true) { | |
487 | + $ret .= $key; | |
488 | + } else { | |
489 | + switch ($this->_[HDOM_INFO_QUOTE][$i]) | |
490 | + { | |
491 | + case HDOM_QUOTE_DOUBLE: $quote = '"'; break; | |
492 | + case HDOM_QUOTE_SINGLE: $quote = '\''; break; | |
493 | + default: $quote = ''; | |
494 | + } | |
495 | + | |
496 | + $ret .= $key | |
497 | + . $this->_[HDOM_INFO_SPACE][$i][1] | |
498 | + . '=' | |
499 | + . $this->_[HDOM_INFO_SPACE][$i][2] | |
500 | + . $quote | |
501 | + . $val | |
502 | + . $quote; | |
503 | + } | |
504 | + } | |
505 | + | |
506 | + $ret = $this->dom->restore_noise($ret); | |
507 | + return $ret . $this->_[HDOM_INFO_ENDSPACE] . '>'; | |
508 | + } | |
509 | + | |
510 | + function find($selector, $idx = null, $lowercase = false) | |
511 | + { | |
512 | + $selectors = $this->parse_selector($selector); | |
513 | + if (($count = count($selectors)) === 0) { return array(); } | |
514 | + $found_keys = array(); | |
515 | + | |
516 | + // find each selector | |
517 | + for ($c = 0; $c < $count; ++$c) { | |
518 | + // The change on the below line was documented on the sourceforge | |
519 | + // code tracker id 2788009 | |
520 | + // used to be: if (($levle=count($selectors[0]))===0) return array(); | |
521 | + if (($levle = count($selectors[$c])) === 0) { return array(); } | |
522 | + if (!isset($this->_[HDOM_INFO_BEGIN])) { return array(); } | |
523 | + | |
524 | + $head = array($this->_[HDOM_INFO_BEGIN] => 1); | |
525 | + $cmd = ' '; // Combinator | |
526 | + | |
527 | + // handle descendant selectors, no recursive! | |
528 | + for ($l = 0; $l < $levle; ++$l) { | |
529 | + $ret = array(); | |
530 | + | |
531 | + foreach ($head as $k => $v) { | |
532 | + $n = ($k === -1) ? $this->dom->root : $this->dom->nodes[$k]; | |
533 | + //PaperG - Pass this optional parameter on to the seek function. | |
534 | + $n->seek($selectors[$c][$l], $ret, $cmd, $lowercase); | |
535 | + } | |
536 | + | |
537 | + $head = $ret; | |
538 | + $cmd = $selectors[$c][$l][4]; // Next Combinator | |
539 | + } | |
540 | + | |
541 | + foreach ($head as $k => $v) { | |
542 | + if (!isset($found_keys[$k])) { | |
543 | + $found_keys[$k] = 1; | |
544 | + } | |
545 | + } | |
546 | + } | |
547 | + | |
548 | + // sort keys | |
549 | + ksort($found_keys); | |
550 | + | |
551 | + $found = array(); | |
552 | + foreach ($found_keys as $k => $v) { | |
553 | + $found[] = $this->dom->nodes[$k]; | |
554 | + } | |
555 | + | |
556 | + // return nth-element or array | |
557 | + if (is_null($idx)) { return $found; } | |
558 | + elseif ($idx < 0) { $idx = count($found) + $idx; } | |
559 | + return (isset($found[$idx])) ? $found[$idx] : null; | |
560 | + } | |
561 | + | |
562 | + protected function seek($selector, &$ret, $parent_cmd, $lowercase = false) | |
563 | + { | |
564 | + global $debug_object; | |
565 | + if (is_object($debug_object)) { $debug_object->debug_log_entry(1); } | |
566 | + | |
567 | + list($tag, $id, $class, $attributes, $cmb) = $selector; | |
568 | + $nodes = array(); | |
569 | + | |
570 | + if ($parent_cmd === ' ') { // Descendant Combinator | |
571 | + // Find parent closing tag if the current element doesn't have a closing | |
572 | + // tag (i.e. void element) | |
573 | + $end = (!empty($this->_[HDOM_INFO_END])) ? $this->_[HDOM_INFO_END] : 0; | |
574 | + if ($end == 0) { | |
575 | + $parent = $this->parent; | |
576 | + while (!isset($parent->_[HDOM_INFO_END]) && $parent !== null) { | |
577 | + $end -= 1; | |
578 | + $parent = $parent->parent; | |
579 | + } | |
580 | + $end += $parent->_[HDOM_INFO_END]; | |
581 | + } | |
582 | + | |
583 | + // Get list of target nodes | |
584 | + $nodes_start = $this->_[HDOM_INFO_BEGIN] + 1; | |
585 | + $nodes_count = $end - $nodes_start; | |
586 | + $nodes = array_slice($this->dom->nodes, $nodes_start, $nodes_count, true); | |
587 | + } elseif ($parent_cmd === '>') { // Child Combinator | |
588 | + $nodes = $this->children; | |
589 | + } elseif ($parent_cmd === '+' | |
590 | + && $this->parent | |
591 | + && in_array($this, $this->parent->children)) { // Next-Sibling Combinator | |
592 | + $index = array_search($this, $this->parent->children, true) + 1; | |
593 | + if ($index < count($this->parent->children)) | |
594 | + $nodes[] = $this->parent->children[$index]; | |
595 | + } elseif ($parent_cmd === '~' | |
596 | + && $this->parent | |
597 | + && in_array($this, $this->parent->children)) { // Subsequent Sibling Combinator | |
598 | + $index = array_search($this, $this->parent->children, true); | |
599 | + $nodes = array_slice($this->parent->children, $index); | |
600 | + } | |
601 | + | |
602 | + // Go throgh each element starting at this element until the end tag | |
603 | + // Note: If this element is a void tag, any previous void element is | |
604 | + // skipped. | |
605 | + foreach($nodes as $node) { | |
606 | + $pass = true; | |
607 | + | |
608 | + // Skip root nodes | |
609 | + if(!$node->parent) { | |
610 | + $pass = false; | |
611 | + } | |
612 | + | |
613 | + // Skip if node isn't a child node (i.e. text nodes) | |
614 | + if($pass && !in_array($node, $node->parent->children, true)) { | |
615 | + $pass = false; | |
616 | + } | |
617 | + | |
618 | + // Skip if tag doesn't match | |
619 | + if ($pass && $tag !== '' && $tag !== $node->tag && $tag !== '*') { | |
620 | + $pass = false; | |
621 | + } | |
622 | + | |
623 | + // Skip if ID doesn't exist | |
624 | + if ($pass && $id !== '' && !isset($node->attr['id'])) { | |
625 | + $pass = false; | |
626 | + } | |
627 | + | |
628 | + // Check if ID matches | |
629 | + if ($pass && $id !== '' && isset($node->attr['id'])) { | |
630 | + // Note: Only consider the first ID (as browsers do) | |
631 | + $node_id = explode(' ', trim($node->attr['id']))[0]; | |
632 | + | |
633 | + if($id !== $node_id) { $pass = false; } | |
634 | + } | |
635 | + | |
636 | + // Check if all class(es) exist | |
637 | + if ($pass && $class !== '' && is_array($class) && !empty($class)) { | |
638 | + if (isset($node->attr['class'])) { | |
639 | + $node_classes = explode(' ', $node->attr['class']); | |
640 | + | |
641 | + if ($lowercase) { | |
642 | + $node_classes = array_map('strtolower', $node_classes); | |
643 | + } | |
644 | + | |
645 | + foreach($class as $c) { | |
646 | + if(!in_array($c, $node_classes)) { | |
647 | + $pass = false; | |
648 | + break; | |
649 | + } | |
650 | + } | |
651 | + } else { | |
652 | + $pass = false; | |
653 | + } | |
654 | + } | |
655 | + | |
656 | + // Check attributes | |
657 | + if ($pass | |
658 | + && $attributes !== '' | |
659 | + && is_array($attributes) | |
660 | + && !empty($attributes)) { | |
661 | + foreach($attributes as $a) { | |
662 | + list ( | |
663 | + $att_name, | |
664 | + $att_expr, | |
665 | + $att_val, | |
666 | + $att_inv, | |
667 | + $att_case_sensitivity | |
668 | + ) = $a; | |
669 | + | |
670 | + // Handle indexing attributes (i.e. "[2]") | |
671 | + /** | |
672 | + * Note: This is not supported by the CSS Standard but adds | |
673 | + * the ability to select items compatible to XPath (i.e. | |
674 | + * the 3rd element within it's parent). | |
675 | + * | |
676 | + * Note: This doesn't conflict with the CSS Standard which | |
677 | + * doesn't work on numeric attributes anyway. | |
678 | + */ | |
679 | + if (is_numeric($att_name) | |
680 | + && $att_expr === '' | |
681 | + && $att_val === '') { | |
682 | + $count = 0; | |
683 | + | |
684 | + // Find index of current element in parent | |
685 | + foreach ($node->parent->children as $c) { | |
686 | + if ($c->tag === $node->tag) ++$count; | |
687 | + if ($c === $node) break; | |
688 | + } | |
689 | + | |
690 | + // If this is the correct node, continue with next | |
691 | + // attribute | |
692 | + if ($count === (int)$att_name) continue; | |
693 | + } | |
694 | + | |
695 | + // Check attribute availability | |
696 | + if ($att_inv) { // Attribute should NOT be set | |
697 | + if (isset($node->attr[$att_name])) { | |
698 | + $pass = false; | |
699 | + break; | |
700 | + } | |
701 | + } else { // Attribute should be set | |
702 | + // todo: "plaintext" is not a valid CSS selector! | |
703 | + if ($att_name !== 'plaintext' | |
704 | + && !isset($node->attr[$att_name])) { | |
705 | + $pass = false; | |
706 | + break; | |
707 | + } | |
708 | + } | |
709 | + | |
710 | + // Continue with next attribute if expression isn't defined | |
711 | + if ($att_expr === '') continue; | |
712 | + | |
713 | + // If they have told us that this is a "plaintext" | |
714 | + // search then we want the plaintext of the node - right? | |
715 | + // todo "plaintext" is not a valid CSS selector! | |
716 | + if ($att_name === 'plaintext') { | |
717 | + $nodeKeyValue = $node->text(); | |
718 | + } else { | |
719 | + $nodeKeyValue = $node->attr[$att_name]; | |
720 | + } | |
721 | + | |
722 | + if (is_object($debug_object)) { | |
723 | + $debug_object->debug_log(2, | |
724 | + 'testing node: ' | |
725 | + . $node->tag | |
726 | + . ' for attribute: ' | |
727 | + . $att_name | |
728 | + . $att_expr | |
729 | + . $att_val | |
730 | + . ' where nodes value is: ' | |
731 | + . $nodeKeyValue | |
732 | + ); | |
733 | + } | |
734 | + | |
735 | + // If lowercase is set, do a case insensitive test of | |
736 | + // the value of the selector. | |
737 | + if ($lowercase) { | |
738 | + $check = $this->match( | |
739 | + $att_expr, | |
740 | + strtolower($att_val), | |
741 | + strtolower($nodeKeyValue), | |
742 | + $att_case_sensitivity | |
743 | + ); | |
744 | + } else { | |
745 | + $check = $this->match( | |
746 | + $att_expr, | |
747 | + $att_val, | |
748 | + $nodeKeyValue, | |
749 | + $att_case_sensitivity | |
750 | + ); | |
751 | + } | |
752 | + | |
753 | + if (is_object($debug_object)) { | |
754 | + $debug_object->debug_log(2, | |
755 | + 'after match: ' | |
756 | + . ($check ? 'true' : 'false') | |
757 | + ); | |
758 | + } | |
759 | + | |
760 | + if (!$check) { | |
761 | + $pass = false; | |
762 | + break; | |
763 | + } | |
764 | + } | |
765 | + } | |
766 | + | |
767 | + // Found a match. Add to list and clear node | |
768 | + if ($pass) $ret[$node->_[HDOM_INFO_BEGIN]] = 1; | |
769 | + unset($node); | |
770 | + } | |
771 | + // It's passed by reference so this is actually what this function returns. | |
772 | + if (is_object($debug_object)) { | |
773 | + $debug_object->debug_log(1, 'EXIT - ret: ', $ret); | |
774 | + } | |
775 | + } | |
776 | + | |
777 | + protected function match($exp, $pattern, $value, $case_sensitivity) | |
778 | + { | |
779 | + global $debug_object; | |
780 | + if (is_object($debug_object)) {$debug_object->debug_log_entry(1);} | |
781 | + | |
782 | + if ($case_sensitivity === 'i') { | |
783 | + $pattern = strtolower($pattern); | |
784 | + $value = strtolower($value); | |
785 | + } | |
786 | + | |
787 | + switch ($exp) { | |
788 | + case '=': | |
789 | + return ($value === $pattern); | |
790 | + case '!=': | |
791 | + return ($value !== $pattern); | |
792 | + case '^=': | |
793 | + return preg_match('/^' . preg_quote($pattern, '/') . '/', $value); | |
794 | + case '$=': | |
795 | + return preg_match('/' . preg_quote($pattern, '/') . '$/', $value); | |
796 | + case '*=': | |
797 | + return preg_match('/' . preg_quote($pattern, '/') . '/', $value); | |
798 | + case '|=': | |
799 | + /** | |
800 | + * [att|=val] | |
801 | + * | |
802 | + * Represents an element with the att attribute, its value | |
803 | + * either being exactly "val" or beginning with "val" | |
804 | + * immediately followed by "-" (U+002D). | |
805 | + */ | |
806 | + return strpos($value, $pattern) === 0; | |
807 | + case '~=': | |
808 | + /** | |
809 | + * [att~=val] | |
810 | + * | |
811 | + * Represents an element with the att attribute whose value is a | |
812 | + * whitespace-separated list of words, one of which is exactly | |
813 | + * "val". If "val" contains whitespace, it will never represent | |
814 | + * anything (since the words are separated by spaces). Also if | |
815 | + * "val" is the empty string, it will never represent anything. | |
816 | + */ | |
817 | + return in_array($pattern, explode(' ', trim($value)), true); | |
818 | + } | |
819 | + return false; | |
820 | + } | |
821 | + | |
822 | + protected function parse_selector($selector_string) | |
823 | + { | |
824 | + global $debug_object; | |
825 | + if (is_object($debug_object)) { $debug_object->debug_log_entry(1); } | |
826 | + | |
827 | + /** | |
828 | + * Pattern of CSS selectors, modified from mootools (https://mootools.net/) | |
829 | + * | |
830 | + * Paperg: Add the colon to the attribute, so that it properly finds | |
831 | + * <tag attr:ibute="something" > like google does. | |
832 | + * | |
833 | + * Note: if you try to look at this attribute, you MUST use getAttribute | |
834 | + * since $dom->x:y will fail the php syntax check. | |
835 | + * | |
836 | + * Notice the \[ starting the attribute? and the @? following? This | |
837 | + * implies that an attribute can begin with an @ sign that is not | |
838 | + * captured. This implies that an html attribute specifier may start | |
839 | + * with an @ sign that is NOT captured by the expression. Farther study | |
840 | + * is required to determine of this should be documented or removed. | |
841 | + * | |
842 | + * Matches selectors in this order: | |
843 | + * | |
844 | + * [0] - full match | |
845 | + * | |
846 | + * [1] - tag name | |
847 | + * ([\w:\*-]*) | |
848 | + * Matches the tag name consisting of zero or more words, colons, | |
849 | + * asterisks and hyphens. | |
850 | + * | |
851 | + * [2] - id name | |
852 | + * (?:\#([\w-]+)) | |
853 | + * Optionally matches a id name, consisting of an "#" followed by | |
854 | + * the id name (one or more words and hyphens). | |
855 | + * | |
856 | + * [3] - class names (including dots) | |
857 | + * (?:\.([\w\.-]+))? | |
858 | + * Optionally matches a list of classs, consisting of an "." | |
859 | + * followed by the class name (one or more words and hyphens) | |
860 | + * where multiple classes can be chained (i.e. ".foo.bar.baz") | |
861 | + * | |
862 | + * [4] - attributes | |
863 | + * ((?:\[@?(?:!?[\w:-]+)(?:(?:[!*^$|~]?=)[\"']?(?:.*?)[\"']?)?(?:\s*?(?:[iIsS])?)?\])+)? | |
864 | + * Optionally matches the attributes list | |
865 | + * | |
866 | + * [5] - separator | |
867 | + * ([\/, >+~]+) | |
868 | + * Matches the selector list separator | |
869 | + */ | |
870 | + // phpcs:ignore Generic.Files.LineLength | |
871 | + $pattern = "/([\w:\*-]*)(?:\#([\w-]+))?(?:|\.([\w\.-]+))?((?:\[@?(?:!?[\w:-]+)(?:(?:[!*^$|~]?=)[\"']?(?:.*?)[\"']?)?(?:\s*?(?:[iIsS])?)?\])+)?([\/, >+~]+)/is"; | |
872 | + | |
873 | + preg_match_all( | |
874 | + $pattern, | |
875 | + trim($selector_string) . ' ', // Add final ' ' as pseudo separator | |
876 | + $matches, | |
877 | + PREG_SET_ORDER | |
878 | + ); | |
879 | + | |
880 | + if (is_object($debug_object)) { | |
881 | + $debug_object->debug_log(2, 'Matches Array: ', $matches); | |
882 | + } | |
883 | + | |
884 | + $selectors = array(); | |
885 | + $result = array(); | |
886 | + | |
887 | + foreach ($matches as $m) { | |
888 | + $m[0] = trim($m[0]); | |
889 | + | |
890 | + // Skip NoOps | |
891 | + if ($m[0] === '' || $m[0] === '/' || $m[0] === '//') { continue; } | |
892 | + | |
893 | + // Convert to lowercase | |
894 | + if ($this->dom->lowercase) { | |
895 | + $m[1] = strtolower($m[1]); | |
896 | + } | |
897 | + | |
898 | + // Extract classes | |
899 | + if ($m[3] !== '') { $m[3] = explode('.', $m[3]); } | |
900 | + | |
901 | + /* Extract attributes (pattern based on the pattern above!) | |
902 | + | |
903 | + * [0] - full match | |
904 | + * [1] - attribute name | |
905 | + * [2] - attribute expression | |
906 | + * [3] - attribute value | |
907 | + * [4] - case sensitivity | |
908 | + * | |
909 | + * Note: Attributes can be negated with a "!" prefix to their name | |
910 | + */ | |
911 | + if($m[4] !== '') { | |
912 | + preg_match_all( | |
913 | + "/\[@?(!?[\w:-]+)(?:([!*^$|~]?=)[\"']?(.*?)[\"']?)?(?:\s+?([iIsS])?)?\]/is", | |
914 | + trim($m[4]), | |
915 | + $attributes, | |
916 | + PREG_SET_ORDER | |
917 | + ); | |
918 | + | |
919 | + // Replace element by array | |
920 | + $m[4] = array(); | |
921 | + | |
922 | + foreach($attributes as $att) { | |
923 | + // Skip empty matches | |
924 | + if(trim($att[0]) === '') { continue; } | |
925 | + | |
926 | + $inverted = (isset($att[1][0]) && $att[1][0] === '!'); | |
927 | + $m[4][] = array( | |
928 | + $inverted ? substr($att[1], 1) : $att[1], // Name | |
929 | + (isset($att[2])) ? $att[2] : '', // Expression | |
930 | + (isset($att[3])) ? $att[3] : '', // Value | |
931 | + $inverted, // Inverted Flag | |
932 | + (isset($att[4])) ? strtolower($att[4]) : '', // Case-Sensitivity | |
933 | + ); | |
934 | + } | |
935 | + } | |
936 | + | |
937 | + // Sanitize Separator | |
938 | + if ($m[5] !== '' && trim($m[5]) === '') { // Descendant Separator | |
939 | + $m[5] = ' '; | |
940 | + } else { // Other Separator | |
941 | + $m[5] = trim($m[5]); | |
942 | + } | |
943 | + | |
944 | + // Clear Separator if it's a Selector List | |
945 | + if ($is_list = ($m[5] === ',')) { $m[5] = ''; } | |
946 | + | |
947 | + // Remove full match before adding to results | |
948 | + array_shift($m); | |
949 | + $result[] = $m; | |
950 | + | |
951 | + if ($is_list) { // Selector List | |
952 | + $selectors[] = $result; | |
953 | + $result = array(); | |
954 | + } | |
955 | + } | |
956 | + | |
957 | + if (count($result) > 0) { $selectors[] = $result; } | |
958 | + return $selectors; | |
959 | + } | |
960 | + | |
961 | + function __get($name) | |
962 | + { | |
963 | + if (isset($this->attr[$name])) { | |
964 | + return $this->convert_text($this->attr[$name]); | |
965 | + } | |
966 | + switch ($name) { | |
967 | + case 'outertext': return $this->outertext(); | |
968 | + case 'innertext': return $this->innertext(); | |
969 | + case 'plaintext': return $this->text(); | |
970 | + case 'xmltext': return $this->xmltext(); | |
971 | + default: return array_key_exists($name, $this->attr); | |
972 | + } | |
973 | + } | |
974 | + | |
975 | + function __set($name, $value) | |
976 | + { | |
977 | + global $debug_object; | |
978 | + if (is_object($debug_object)) { $debug_object->debug_log_entry(1); } | |
979 | + | |
980 | + switch ($name) { | |
981 | + case 'outertext': return $this->_[HDOM_INFO_OUTER] = $value; | |
982 | + case 'innertext': | |
983 | + if (isset($this->_[HDOM_INFO_TEXT])) { | |
984 | + return $this->_[HDOM_INFO_TEXT] = $value; | |
985 | + } | |
986 | + return $this->_[HDOM_INFO_INNER] = $value; | |
987 | + } | |
988 | + | |
989 | + if (!isset($this->attr[$name])) { | |
990 | + $this->_[HDOM_INFO_SPACE][] = array(' ', '', ''); | |
991 | + $this->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_DOUBLE; | |
992 | + } | |
993 | + | |
994 | + $this->attr[$name] = $value; | |
995 | + } | |
996 | + | |
997 | + function __isset($name) | |
998 | + { | |
999 | + switch ($name) { | |
1000 | + case 'outertext': return true; | |
1001 | + case 'innertext': return true; | |
1002 | + case 'plaintext': return true; | |
1003 | + } | |
1004 | + //no value attr: nowrap, checked selected... | |
1005 | + return (array_key_exists($name, $this->attr)) ? true : isset($this->attr[$name]); | |
1006 | + } | |
1007 | + | |
1008 | + function __unset($name) | |
1009 | + { | |
1010 | + if (isset($this->attr[$name])) { unset($this->attr[$name]); } | |
1011 | + } | |
1012 | + | |
1013 | + function convert_text($text) | |
1014 | + { | |
1015 | + global $debug_object; | |
1016 | + if (is_object($debug_object)) { $debug_object->debug_log_entry(1); } | |
1017 | + | |
1018 | + $converted_text = $text; | |
1019 | + | |
1020 | + $sourceCharset = ''; | |
1021 | + $targetCharset = ''; | |
1022 | + | |
1023 | + if ($this->dom) { | |
1024 | + $sourceCharset = strtoupper($this->dom->_charset); | |
1025 | + $targetCharset = strtoupper($this->dom->_target_charset); | |
1026 | + } | |
1027 | + | |
1028 | + if (is_object($debug_object)) { | |
1029 | + $debug_object->debug_log(3, | |
1030 | + 'source charset: ' | |
1031 | + . $sourceCharset | |
1032 | + . ' target charaset: ' | |
1033 | + . $targetCharset | |
1034 | + ); | |
1035 | + } | |
1036 | + | |
1037 | + if (!empty($sourceCharset) | |
1038 | + && !empty($targetCharset) | |
1039 | + && (strcasecmp($sourceCharset, $targetCharset) != 0)) { | |
1040 | + // Check if the reported encoding could have been incorrect and the text is actually already UTF-8 | |
1041 | + if ((strcasecmp($targetCharset, 'UTF-8') == 0) | |
1042 | + && ($this->is_utf8($text))) { | |
1043 | + $converted_text = $text; | |
1044 | + } else { | |
1045 | + $converted_text = iconv($sourceCharset, $targetCharset, $text); | |
1046 | + } | |
1047 | + } | |
1048 | + | |
1049 | + // Lets make sure that we don't have that silly BOM issue with any of the utf-8 text we output. | |
1050 | + if ($targetCharset === 'UTF-8') { | |
1051 | + if (substr($converted_text, 0, 3) === "\xef\xbb\xbf") { | |
1052 | + $converted_text = substr($converted_text, 3); | |
1053 | + } | |
1054 | + | |
1055 | + if (substr($converted_text, -3) === "\xef\xbb\xbf") { | |
1056 | + $converted_text = substr($converted_text, 0, -3); | |
1057 | + } | |
1058 | + } | |
1059 | + | |
1060 | + return $converted_text; | |
1061 | + } | |
1062 | + | |
1063 | + static function is_utf8($str) | |
1064 | + { | |
1065 | + $c = 0; $b = 0; | |
1066 | + $bits = 0; | |
1067 | + $len = strlen($str); | |
1068 | + for($i = 0; $i < $len; $i++) { | |
1069 | + $c = ord($str[$i]); | |
1070 | + if($c > 128) { | |
1071 | + if(($c >= 254)) { return false; } | |
1072 | + elseif($c >= 252) { $bits = 6; } | |
1073 | + elseif($c >= 248) { $bits = 5; } | |
1074 | + elseif($c >= 240) { $bits = 4; } | |
1075 | + elseif($c >= 224) { $bits = 3; } | |
1076 | + elseif($c >= 192) { $bits = 2; } | |
1077 | + else { return false; } | |
1078 | + if(($i + $bits) > $len) { return false; } | |
1079 | + while($bits > 1) { | |
1080 | + $i++; | |
1081 | + $b = ord($str[$i]); | |
1082 | + if($b < 128 || $b > 191) { return false; } | |
1083 | + $bits--; | |
1084 | + } | |
1085 | + } | |
1086 | + } | |
1087 | + return true; | |
1088 | + } | |
1089 | + | |
1090 | + function get_display_size() | |
1091 | + { | |
1092 | + global $debug_object; | |
1093 | + | |
1094 | + $width = -1; | |
1095 | + $height = -1; | |
1096 | + | |
1097 | + if ($this->tag !== 'img') { | |
1098 | + return false; | |
1099 | + } | |
1100 | + | |
1101 | + // See if there is aheight or width attribute in the tag itself. | |
1102 | + if (isset($this->attr['width'])) { | |
1103 | + $width = $this->attr['width']; | |
1104 | + } | |
1105 | + | |
1106 | + if (isset($this->attr['height'])) { | |
1107 | + $height = $this->attr['height']; | |
1108 | + } | |
1109 | + | |
1110 | + // Now look for an inline style. | |
1111 | + if (isset($this->attr['style'])) { | |
1112 | + // Thanks to user gnarf from stackoverflow for this regular expression. | |
1113 | + $attributes = array(); | |
1114 | + | |
1115 | + preg_match_all( | |
1116 | + '/([\w-]+)\s*:\s*([^;]+)\s*;?/', | |
1117 | + $this->attr['style'], | |
1118 | + $matches, | |
1119 | + PREG_SET_ORDER | |
1120 | + ); | |
1121 | + | |
1122 | + foreach ($matches as $match) { | |
1123 | + $attributes[$match[1]] = $match[2]; | |
1124 | + } | |
1125 | + | |
1126 | + // If there is a width in the style attributes: | |
1127 | + if (isset($attributes['width']) && $width == -1) { | |
1128 | + // check that the last two characters are px (pixels) | |
1129 | + if (strtolower(substr($attributes['width'], -2)) === 'px') { | |
1130 | + $proposed_width = substr($attributes['width'], 0, -2); | |
1131 | + // Now make sure that it's an integer and not something stupid. | |
1132 | + if (filter_var($proposed_width, FILTER_VALIDATE_INT)) { | |
1133 | + $width = $proposed_width; | |
1134 | + } | |
1135 | + } | |
1136 | + } | |
1137 | + | |
1138 | + // If there is a width in the style attributes: | |
1139 | + if (isset($attributes['height']) && $height == -1) { | |
1140 | + // check that the last two characters are px (pixels) | |
1141 | + if (strtolower(substr($attributes['height'], -2)) == 'px') { | |
1142 | + $proposed_height = substr($attributes['height'], 0, -2); | |
1143 | + // Now make sure that it's an integer and not something stupid. | |
1144 | + if (filter_var($proposed_height, FILTER_VALIDATE_INT)) { | |
1145 | + $height = $proposed_height; | |
1146 | + } | |
1147 | + } | |
1148 | + } | |
1149 | + | |
1150 | + } | |
1151 | + | |
1152 | + // Future enhancement: | |
1153 | + // Look in the tag to see if there is a class or id specified that has | |
1154 | + // a height or width attribute to it. | |
1155 | + | |
1156 | + // Far future enhancement | |
1157 | + // Look at all the parent tags of this image to see if they specify a | |
1158 | + // class or id that has an img selector that specifies a height or width | |
1159 | + // Note that in this case, the class or id will have the img subselector | |
1160 | + // for it to apply to the image. | |
1161 | + | |
1162 | + // ridiculously far future development | |
1163 | + // If the class or id is specified in a SEPARATE css file thats not on | |
1164 | + // the page, go get it and do what we were just doing for the ones on | |
1165 | + // the page. | |
1166 | + | |
1167 | + $result = array( | |
1168 | + 'height' => $height, | |
1169 | + 'width' => $width | |
1170 | + ); | |
1171 | + | |
1172 | + return $result; | |
1173 | + } | |
1174 | + | |
1175 | + function save($filepath = '') | |
1176 | + { | |
1177 | + $ret = $this->outertext(); | |
1178 | + | |
1179 | + if ($filepath !== '') { | |
1180 | + file_put_contents($filepath, $ret, LOCK_EX); | |
1181 | + } | |
1182 | + | |
1183 | + return $ret; | |
1184 | + } | |
1185 | + | |
1186 | + function addClass($class) | |
1187 | + { | |
1188 | + if (is_string($class)) { | |
1189 | + $class = explode(' ', $class); | |
1190 | + } | |
1191 | + | |
1192 | + if (is_array($class)) { | |
1193 | + foreach($class as $c) { | |
1194 | + if (isset($this->class)) { | |
1195 | + if ($this->hasClass($c)) { | |
1196 | + continue; | |
1197 | + } else { | |
1198 | + $this->class .= ' ' . $c; | |
1199 | + } | |
1200 | + } else { | |
1201 | + $this->class = $c; | |
1202 | + } | |
1203 | + } | |
1204 | + } else { | |
1205 | + if (is_object($debug_object)) { | |
1206 | + $debug_object->debug_log(2, 'Invalid type: ', gettype($class)); | |
1207 | + } | |
1208 | + } | |
1209 | + } | |
1210 | + | |
1211 | + function hasClass($class) | |
1212 | + { | |
1213 | + if (is_string($class)) { | |
1214 | + if (isset($this->class)) { | |
1215 | + return in_array($class, explode(' ', $this->class), true); | |
1216 | + } | |
1217 | + } else { | |
1218 | + if (is_object($debug_object)) { | |
1219 | + $debug_object->debug_log(2, 'Invalid type: ', gettype($class)); | |
1220 | + } | |
1221 | + } | |
1222 | + | |
1223 | + return false; | |
1224 | + } | |
1225 | + | |
1226 | + function removeClass($class = null) | |
1227 | + { | |
1228 | + if (!isset($this->class)) { | |
1229 | + return; | |
1230 | + } | |
1231 | + | |
1232 | + if (is_null($class)) { | |
1233 | + $this->removeAttribute('class'); | |
1234 | + return; | |
1235 | + } | |
1236 | + | |
1237 | + if (is_string($class)) { | |
1238 | + $class = explode(' ', $class); | |
1239 | + } | |
1240 | + | |
1241 | + if (is_array($class)) { | |
1242 | + $class = array_diff(explode(' ', $this->class), $class); | |
1243 | + if (empty($class)) { | |
1244 | + $this->removeAttribute('class'); | |
1245 | + } else { | |
1246 | + $this->class = implode(' ', $class); | |
1247 | + } | |
1248 | + } | |
1249 | + } | |
1250 | + | |
1251 | + function getAllAttributes() | |
1252 | + { | |
1253 | + return $this->attr; | |
1254 | + } | |
1255 | + | |
1256 | + function getAttribute($name) | |
1257 | + { | |
1258 | + return $this->__get($name); | |
1259 | + } | |
1260 | + | |
1261 | + function setAttribute($name, $value) | |
1262 | + { | |
1263 | + $this->__set($name, $value); | |
1264 | + } | |
1265 | + | |
1266 | + function hasAttribute($name) | |
1267 | + { | |
1268 | + return $this->__isset($name); | |
1269 | + } | |
1270 | + | |
1271 | + function removeAttribute($name) | |
1272 | + { | |
1273 | + $this->__set($name, null); | |
1274 | + } | |
1275 | + | |
1276 | + function remove() | |
1277 | + { | |
1278 | + if ($this->parent) { | |
1279 | + $this->parent->removeChild($this); | |
1280 | + } | |
1281 | + } | |
1282 | + | |
1283 | + function removeChild($node) | |
1284 | + { | |
1285 | + $nidx = array_search($node, $this->nodes, true); | |
1286 | + $cidx = array_search($node, $this->children, true); | |
1287 | + $didx = array_search($node, $this->dom->nodes, true); | |
1288 | + | |
1289 | + if ($nidx !== false && $cidx !== false && $didx !== false) { | |
1290 | + | |
1291 | + foreach($node->children as $child) { | |
1292 | + $node->removeChild($child); | |
1293 | + } | |
1294 | + | |
1295 | + foreach($node->nodes as $entity) { | |
1296 | + $enidx = array_search($entity, $node->nodes, true); | |
1297 | + $edidx = array_search($entity, $node->dom->nodes, true); | |
1298 | + | |
1299 | + if ($enidx !== false && $edidx !== false) { | |
1300 | + unset($node->nodes[$enidx]); | |
1301 | + unset($node->dom->nodes[$edidx]); | |
1302 | + } | |
1303 | + } | |
1304 | + | |
1305 | + unset($this->nodes[$nidx]); | |
1306 | + unset($this->children[$cidx]); | |
1307 | + unset($this->dom->nodes[$didx]); | |
1308 | + | |
1309 | + $node->clear(); | |
1310 | + | |
1311 | + } | |
1312 | + } | |
1313 | + | |
1314 | + function getElementById($id) | |
1315 | + { | |
1316 | + return $this->find("#$id", 0); | |
1317 | + } | |
1318 | + | |
1319 | + function getElementsById($id, $idx = null) | |
1320 | + { | |
1321 | + return $this->find("#$id", $idx); | |
1322 | + } | |
1323 | + | |
1324 | + function getElementByTagName($name) | |
1325 | + { | |
1326 | + return $this->find($name, 0); | |
1327 | + } | |
1328 | + | |
1329 | + function getElementsByTagName($name, $idx = null) | |
1330 | + { | |
1331 | + return $this->find($name, $idx); | |
1332 | + } | |
1333 | + | |
1334 | + function parentNode() | |
1335 | + { | |
1336 | + return $this->parent(); | |
1337 | + } | |
1338 | + | |
1339 | + function childNodes($idx = -1) | |
1340 | + { | |
1341 | + return $this->children($idx); | |
1342 | + } | |
1343 | + | |
1344 | + function firstChild() | |
1345 | + { | |
1346 | + return $this->first_child(); | |
1347 | + } | |
1348 | + | |
1349 | + function lastChild() | |
1350 | + { | |
1351 | + return $this->last_child(); | |
1352 | + } | |
1353 | + | |
1354 | + function nextSibling() | |
1355 | + { | |
1356 | + return $this->next_sibling(); | |
1357 | + } | |
1358 | + | |
1359 | + function previousSibling() | |
1360 | + { | |
1361 | + return $this->prev_sibling(); | |
1362 | + } | |
1363 | + | |
1364 | + function hasChildNodes() | |
1365 | + { | |
1366 | + return $this->has_child(); | |
1367 | + } | |
1368 | + | |
1369 | + function nodeName() | |
1370 | + { | |
1371 | + return $this->tag; | |
1372 | + } | |
1373 | + | |
1374 | + function appendChild($node) | |
1375 | + { | |
1376 | + $node->parent($this); | |
1377 | + return $node; | |
1378 | + } | |
1379 | + | |
1380 | +} | |
1381 | + | |
1382 | +class simple_html_dom | |
1383 | +{ | |
1384 | + public $root = null; | |
1385 | + public $nodes = array(); | |
1386 | + public $callback = null; | |
1387 | + public $lowercase = false; | |
1388 | + public $original_size; | |
1389 | + public $size; | |
1390 | + | |
1391 | + protected $pos; | |
1392 | + protected $doc; | |
1393 | + protected $char; | |
1394 | + | |
1395 | + protected $cursor; | |
1396 | + protected $parent; | |
1397 | + protected $noise = array(); | |
1398 | + protected $token_blank = " \t\r\n"; | |
1399 | + protected $token_equal = ' =/>'; | |
1400 | + protected $token_slash = " />\r\n\t"; | |
1401 | + protected $token_attr = ' >'; | |
1402 | + | |
1403 | + public $_charset = ''; | |
1404 | + public $_target_charset = ''; | |
1405 | + | |
1406 | + protected $default_br_text = ''; | |
1407 | + | |
1408 | + public $default_span_text = ''; | |
1409 | + | |
1410 | + protected $self_closing_tags = array( | |
1411 | + 'area' => 1, | |
1412 | + 'base' => 1, | |
1413 | + 'br' => 1, | |
1414 | + 'col' => 1, | |
1415 | + 'embed' => 1, | |
1416 | + 'hr' => 1, | |
1417 | + 'img' => 1, | |
1418 | + 'input' => 1, | |
1419 | + 'link' => 1, | |
1420 | + 'meta' => 1, | |
1421 | + 'param' => 1, | |
1422 | + 'source' => 1, | |
1423 | + 'track' => 1, | |
1424 | + 'wbr' => 1 | |
1425 | + ); | |
1426 | + protected $block_tags = array( | |
1427 | + 'body' => 1, | |
1428 | + 'div' => 1, | |
1429 | + 'form' => 1, | |
1430 | + 'root' => 1, | |
1431 | + 'span' => 1, | |
1432 | + 'table' => 1 | |
1433 | + ); | |
1434 | + protected $optional_closing_tags = array( | |
1435 | + // Not optional, see | |
1436 | + // https://www.w3.org/TR/html/textlevel-semantics.html#the-b-element | |
1437 | + 'b' => array('b' => 1), | |
1438 | + 'dd' => array('dd' => 1, 'dt' => 1), | |
1439 | + // Not optional, see | |
1440 | + // https://www.w3.org/TR/html/grouping-content.html#the-dl-element | |
1441 | + 'dl' => array('dd' => 1, 'dt' => 1), | |
1442 | + 'dt' => array('dd' => 1, 'dt' => 1), | |
1443 | + 'li' => array('li' => 1), | |
1444 | + 'optgroup' => array('optgroup' => 1, 'option' => 1), | |
1445 | + 'option' => array('optgroup' => 1, 'option' => 1), | |
1446 | + 'p' => array('p' => 1), | |
1447 | + 'rp' => array('rp' => 1, 'rt' => 1), | |
1448 | + 'rt' => array('rp' => 1, 'rt' => 1), | |
1449 | + 'td' => array('td' => 1, 'th' => 1), | |
1450 | + 'th' => array('td' => 1, 'th' => 1), | |
1451 | + 'tr' => array('td' => 1, 'th' => 1, 'tr' => 1), | |
1452 | + ); | |
1453 | + | |
1454 | + function __construct( | |
1455 | + $str = null, | |
1456 | + $lowercase = true, | |
1457 | + $forceTagsClosed = true, | |
1458 | + $target_charset = DEFAULT_TARGET_CHARSET, | |
1459 | + $stripRN = true, | |
1460 | + $defaultBRText = DEFAULT_BR_TEXT, | |
1461 | + $defaultSpanText = DEFAULT_SPAN_TEXT, | |
1462 | + $options = 0) | |
1463 | + { | |
1464 | + if ($str) { | |
1465 | + if (preg_match('/^http:\/\//i', $str) || is_file($str)) { | |
1466 | + $this->load_file($str); | |
1467 | + } else { | |
1468 | + $this->load( | |
1469 | + $str, | |
1470 | + $lowercase, | |
1471 | + $stripRN, | |
1472 | + $defaultBRText, | |
1473 | + $defaultSpanText, | |
1474 | + $options | |
1475 | + ); | |
1476 | + } | |
1477 | + } | |
1478 | + // Forcing tags to be closed implies that we don't trust the html, but | |
1479 | + // it can lead to parsing errors if we SHOULD trust the html. | |
1480 | + if (!$forceTagsClosed) { | |
1481 | + $this->optional_closing_array = array(); | |
1482 | + } | |
1483 | + | |
1484 | + $this->_target_charset = $target_charset; | |
1485 | + } | |
1486 | + | |
1487 | + function __destruct() | |
1488 | + { | |
1489 | + $this->clear(); | |
1490 | + } | |
1491 | + | |
1492 | + function load( | |
1493 | + $str, | |
1494 | + $lowercase = true, | |
1495 | + $stripRN = true, | |
1496 | + $defaultBRText = DEFAULT_BR_TEXT, | |
1497 | + $defaultSpanText = DEFAULT_SPAN_TEXT, | |
1498 | + $options = 0) | |
1499 | + { | |
1500 | + global $debug_object; | |
1501 | + | |
1502 | + // prepare | |
1503 | + $this->prepare($str, $lowercase, $defaultBRText, $defaultSpanText); | |
1504 | + | |
1505 | + // Per sourceforge http://sourceforge.net/tracker/?func=detail&aid=2949097&group_id=218559&atid=1044037 | |
1506 | + // Script tags removal now preceeds style tag removal. | |
1507 | + // strip out <script> tags | |
1508 | + $this->remove_noise("'<\s*script[^>]*[^/]>(.*?)<\s*/\s*script\s*>'is"); | |
1509 | + $this->remove_noise("'<\s*script\s*>(.*?)<\s*/\s*script\s*>'is"); | |
1510 | + | |
1511 | + // strip out the \r \n's if we are told to. | |
1512 | + if ($stripRN) { | |
1513 | + $this->doc = str_replace("\r", ' ', $this->doc); | |
1514 | + $this->doc = str_replace("\n", ' ', $this->doc); | |
1515 | + | |
1516 | + // set the length of content since we have changed it. | |
1517 | + $this->size = strlen($this->doc); | |
1518 | + } | |
1519 | + | |
1520 | + // strip out cdata | |
1521 | + $this->remove_noise("'<!\[CDATA\[(.*?)\]\]>'is", true); | |
1522 | + // strip out comments | |
1523 | + $this->remove_noise("'<!--(.*?)-->'is"); | |
1524 | + // strip out <style> tags | |
1525 | + $this->remove_noise("'<\s*style[^>]*[^/]>(.*?)<\s*/\s*style\s*>'is"); | |
1526 | + $this->remove_noise("'<\s*style\s*>(.*?)<\s*/\s*style\s*>'is"); | |
1527 | + // strip out preformatted tags | |
1528 | + $this->remove_noise("'<\s*(?:code)[^>]*>(.*?)<\s*/\s*(?:code)\s*>'is"); | |
1529 | + // strip out server side scripts | |
1530 | + $this->remove_noise("'(<\?)(.*?)(\?>)'s", true); | |
1531 | + | |
1532 | + if($options & HDOM_SMARTY_AS_TEXT) { // Strip Smarty scripts | |
1533 | + $this->remove_noise("'(\{\w)(.*?)(\})'s", true); | |
1534 | + } | |
1535 | + | |
1536 | + // parsing | |
1537 | + $this->parse(); | |
1538 | + // end | |
1539 | + $this->root->_[HDOM_INFO_END] = $this->cursor; | |
1540 | + $this->parse_charset(); | |
1541 | + | |
1542 | + // make load function chainable | |
1543 | + return $this; | |
1544 | + } | |
1545 | + | |
1546 | + function load_file() | |
1547 | + { | |
1548 | + $args = func_get_args(); | |
1549 | + | |
1550 | + if(($doc = call_user_func_array('file_get_contents', $args)) !== false) { | |
1551 | + $this->load($doc, true); | |
1552 | + } else { | |
1553 | + return false; | |
1554 | + } | |
1555 | + } | |
1556 | + | |
1557 | + function set_callback($function_name) | |
1558 | + { | |
1559 | + $this->callback = $function_name; | |
1560 | + } | |
1561 | + | |
1562 | + function remove_callback() | |
1563 | + { | |
1564 | + $this->callback = null; | |
1565 | + } | |
1566 | + | |
1567 | + function save($filepath = '') | |
1568 | + { | |
1569 | + $ret = $this->root->innertext(); | |
1570 | + if ($filepath !== '') { file_put_contents($filepath, $ret, LOCK_EX); } | |
1571 | + return $ret; | |
1572 | + } | |
1573 | + | |
1574 | + function find($selector, $idx = null, $lowercase = false) | |
1575 | + { | |
1576 | + return $this->root->find($selector, $idx, $lowercase); | |
1577 | + } | |
1578 | + | |
1579 | + function clear() | |
1580 | + { | |
1581 | + if (isset($this->nodes)) { | |
1582 | + foreach ($this->nodes as $n) { | |
1583 | + $n->clear(); | |
1584 | + $n = null; | |
1585 | + } | |
1586 | + } | |
1587 | + | |
1588 | + // This add next line is documented in the sourceforge repository. | |
1589 | + // 2977248 as a fix for ongoing memory leaks that occur even with the | |
1590 | + // use of clear. | |
1591 | + if (isset($this->children)) { | |
1592 | + foreach ($this->children as $n) { | |
1593 | + $n->clear(); | |
1594 | + $n = null; | |
1595 | + } | |
1596 | + } | |
1597 | + | |
1598 | + if (isset($this->parent)) { | |
1599 | + $this->parent->clear(); | |
1600 | + unset($this->parent); | |
1601 | + } | |
1602 | + | |
1603 | + if (isset($this->root)) { | |
1604 | + $this->root->clear(); | |
1605 | + unset($this->root); | |
1606 | + } | |
1607 | + | |
1608 | + unset($this->doc); | |
1609 | + unset($this->noise); | |
1610 | + } | |
1611 | + | |
1612 | + function dump($show_attr = true) | |
1613 | + { | |
1614 | + $this->root->dump($show_attr); | |
1615 | + } | |
1616 | + | |
1617 | + protected function prepare( | |
1618 | + $str, $lowercase = true, | |
1619 | + $defaultBRText = DEFAULT_BR_TEXT, | |
1620 | + $defaultSpanText = DEFAULT_SPAN_TEXT) | |
1621 | + { | |
1622 | + $this->clear(); | |
1623 | + | |
1624 | + $this->doc = trim($str); | |
1625 | + $this->size = strlen($this->doc); | |
1626 | + $this->original_size = $this->size; // original size of the html | |
1627 | + $this->pos = 0; | |
1628 | + $this->cursor = 1; | |
1629 | + $this->noise = array(); | |
1630 | + $this->nodes = array(); | |
1631 | + $this->lowercase = $lowercase; | |
1632 | + $this->default_br_text = $defaultBRText; | |
1633 | + $this->default_span_text = $defaultSpanText; | |
1634 | + $this->root = new simple_html_dom_node($this); | |
1635 | + $this->root->tag = 'root'; | |
1636 | + $this->root->_[HDOM_INFO_BEGIN] = -1; | |
1637 | + $this->root->nodetype = HDOM_TYPE_ROOT; | |
1638 | + $this->parent = $this->root; | |
1639 | + if ($this->size > 0) { $this->char = $this->doc[0]; } | |
1640 | + } | |
1641 | + | |
1642 | + protected function parse() | |
1643 | + { | |
1644 | + while (true) { | |
1645 | + // Read next tag if there is no text between current position and the | |
1646 | + // next opening tag. | |
1647 | + if (($s = $this->copy_until_char('<')) === '') { | |
1648 | + if($this->read_tag()) { | |
1649 | + continue; | |
1650 | + } else { | |
1651 | + return true; | |
1652 | + } | |
1653 | + } | |
1654 | + | |
1655 | + // Add a text node for text between tags | |
1656 | + $node = new simple_html_dom_node($this); | |
1657 | + ++$this->cursor; | |
1658 | + $node->_[HDOM_INFO_TEXT] = $s; | |
1659 | + $this->link_nodes($node, false); | |
1660 | + } | |
1661 | + } | |
1662 | + | |
1663 | + protected function parse_charset() | |
1664 | + { | |
1665 | + global $debug_object; | |
1666 | + | |
1667 | + $charset = null; | |
1668 | + | |
1669 | + if (function_exists('get_last_retrieve_url_contents_content_type')) { | |
1670 | + $contentTypeHeader = get_last_retrieve_url_contents_content_type(); | |
1671 | + $success = preg_match('/charset=(.+)/', $contentTypeHeader, $matches); | |
1672 | + if ($success) { | |
1673 | + $charset = $matches[1]; | |
1674 | + if (is_object($debug_object)) { | |
1675 | + $debug_object->debug_log(2, | |
1676 | + 'header content-type found charset of: ' | |
1677 | + . $charset | |
1678 | + ); | |
1679 | + } | |
1680 | + } | |
1681 | + } | |
1682 | + | |
1683 | + if (empty($charset)) { | |
1684 | + // https://www.w3.org/TR/html/document-metadata.html#statedef-http-equiv-content-type | |
1685 | + $el = $this->root->find('meta[http-equiv=Content-Type]', 0, true); | |
1686 | + | |
1687 | + if (!empty($el)) { | |
1688 | + $fullvalue = $el->content; | |
1689 | + if (is_object($debug_object)) { | |
1690 | + $debug_object->debug_log(2, | |
1691 | + 'meta content-type tag found' | |
1692 | + . $fullvalue | |
1693 | + ); | |
1694 | + } | |
1695 | + | |
1696 | + if (!empty($fullvalue)) { | |
1697 | + $success = preg_match( | |
1698 | + '/charset=(.+)/i', | |
1699 | + $fullvalue, | |
1700 | + $matches | |
1701 | + ); | |
1702 | + | |
1703 | + if ($success) { | |
1704 | + $charset = $matches[1]; | |
1705 | + } else { | |
1706 | + // If there is a meta tag, and they don't specify the | |
1707 | + // character set, research says that it's typically | |
1708 | + // ISO-8859-1 | |
1709 | + if (is_object($debug_object)) { | |
1710 | + $debug_object->debug_log(2, | |
1711 | + 'meta content-type tag couldn\'t be parsed. using iso-8859 default.' | |
1712 | + ); | |
1713 | + } | |
1714 | + | |
1715 | + $charset = 'ISO-8859-1'; | |
1716 | + } | |
1717 | + } | |
1718 | + } | |
1719 | + } | |
1720 | + | |
1721 | + if (empty($charset)) { | |
1722 | + // https://www.w3.org/TR/html/document-metadata.html#character-encoding-declaration | |
1723 | + if ($meta = $this->root->find('meta[charset]', 0)) { | |
1724 | + $charset = $meta->charset; | |
1725 | + if (is_object($debug_object)) { | |
1726 | + $debug_object->debug_log(2, 'meta charset: ' . $charset); | |
1727 | + } | |
1728 | + } | |
1729 | + } | |
1730 | + | |
1731 | + if (empty($charset)) { | |
1732 | + // Try to guess the charset based on the content | |
1733 | + // Requires Multibyte String (mbstring) support (optional) | |
1734 | + if (function_exists('mb_detect_encoding')) { | |
1735 | + /** | |
1736 | + * mb_detect_encoding() is not intended to distinguish between | |
1737 | + * charsets, especially single-byte charsets. Its primary | |
1738 | + * purpose is to detect which multibyte encoding is in use, | |
1739 | + * i.e. UTF-8, UTF-16, shift-JIS, etc. | |
1740 | + * | |
1741 | + * -- https://bugs.php.net/bug.php?id=38138 | |
1742 | + * | |
1743 | + * Adding both CP1251/ISO-8859-5 and CP1252/ISO-8859-1 will | |
1744 | + * always result in CP1251/ISO-8859-5 and vice versa. | |
1745 | + * | |
1746 | + * Thus, only detect if it's either UTF-8 or CP1252/ISO-8859-1 | |
1747 | + * to stay compatible. | |
1748 | + */ | |
1749 | + $encoding = mb_detect_encoding( | |
1750 | + $this->doc, | |
1751 | + array( 'UTF-8', 'CP1252', 'ISO-8859-1' ) | |
1752 | + ); | |
1753 | + | |
1754 | + if ($encoding === 'CP1252' || $encoding === 'ISO-8859-1') { | |
1755 | + // Due to a limitation of mb_detect_encoding | |
1756 | + // 'CP1251'/'ISO-8859-5' will be detected as | |
1757 | + // 'CP1252'/'ISO-8859-1'. This will cause iconv to fail, in | |
1758 | + // which case we can simply assume it is the other charset. | |
1759 | + if (!@iconv('CP1252', 'UTF-8', $this->doc)) { | |
1760 | + $encoding = 'CP1251'; | |
1761 | + } | |
1762 | + } | |
1763 | + | |
1764 | + if ($encoding !== false) { | |
1765 | + $charset = $encoding; | |
1766 | + if (is_object($debug_object)) { | |
1767 | + $debug_object->debug_log(2, 'mb_detect: ' . $charset); | |
1768 | + } | |
1769 | + } | |
1770 | + } | |
1771 | + } | |
1772 | + | |
1773 | + if (empty($charset)) { | |
1774 | + // Assume it's UTF-8 as it is the most likely charset to be used | |
1775 | + $charset = 'UTF-8'; | |
1776 | + if (is_object($debug_object)) { | |
1777 | + $debug_object->debug_log(2, 'No match found, assume ' . $charset); | |
1778 | + } | |
1779 | + } | |
1780 | + | |
1781 | + // Since CP1252 is a superset, if we get one of it's subsets, we want | |
1782 | + // it instead. | |
1783 | + if ((strtolower($charset) == 'iso-8859-1') | |
1784 | + || (strtolower($charset) == 'latin1') | |
1785 | + || (strtolower($charset) == 'latin-1')) { | |
1786 | + $charset = 'CP1252'; | |
1787 | + if (is_object($debug_object)) { | |
1788 | + $debug_object->debug_log(2, | |
1789 | + 'replacing ' . $charset . ' with CP1252 as its a superset' | |
1790 | + ); | |
1791 | + } | |
1792 | + } | |
1793 | + | |
1794 | + if (is_object($debug_object)) { | |
1795 | + $debug_object->debug_log(1, 'EXIT - ' . $charset); | |
1796 | + } | |
1797 | + | |
1798 | + return $this->_charset = $charset; | |
1799 | + } | |
1800 | + | |
1801 | + protected function read_tag() | |
1802 | + { | |
1803 | + // Set end position if no further tags found | |
1804 | + if ($this->char !== '<') { | |
1805 | + $this->root->_[HDOM_INFO_END] = $this->cursor; | |
1806 | + return false; | |
1807 | + } | |
1808 | + | |
1809 | + $begin_tag_pos = $this->pos; | |
1810 | + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next | |
1811 | + | |
1812 | + // end tag | |
1813 | + if ($this->char === '/') { | |
1814 | + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next | |
1815 | + | |
1816 | + // Skip whitespace in end tags (i.e. in "</ html>") | |
1817 | + $this->skip($this->token_blank); | |
1818 | + $tag = $this->copy_until_char('>'); | |
1819 | + | |
1820 | + // Skip attributes in end tags | |
1821 | + if (($pos = strpos($tag, ' ')) !== false) { | |
1822 | + $tag = substr($tag, 0, $pos); | |
1823 | + } | |
1824 | + | |
1825 | + $parent_lower = strtolower($this->parent->tag); | |
1826 | + $tag_lower = strtolower($tag); | |
1827 | + | |
1828 | + // The end tag is supposed to close the parent tag. Handle situations | |
1829 | + // when it doesn't | |
1830 | + if ($parent_lower !== $tag_lower) { | |
1831 | + // Parent tag does not have to be closed necessarily (optional closing tag) | |
1832 | + // Current tag is a block tag, so it may close an ancestor | |
1833 | + if (isset($this->optional_closing_tags[$parent_lower]) | |
1834 | + && isset($this->block_tags[$tag_lower])) { | |
1835 | + | |
1836 | + $this->parent->_[HDOM_INFO_END] = 0; | |
1837 | + $org_parent = $this->parent; | |
1838 | + | |
1839 | + // Traverse ancestors to find a matching opening tag | |
1840 | + // Stop at root node | |
1841 | + while (($this->parent->parent) | |
1842 | + && strtolower($this->parent->tag) !== $tag_lower | |
1843 | + ){ | |
1844 | + $this->parent = $this->parent->parent; | |
1845 | + } | |
1846 | + | |
1847 | + // If we don't have a match add current tag as text node | |
1848 | + if (strtolower($this->parent->tag) !== $tag_lower) { | |
1849 | + $this->parent = $org_parent; // restore origonal parent | |
1850 | + | |
1851 | + if ($this->parent->parent) { | |
1852 | + $this->parent = $this->parent->parent; | |
1853 | + } | |
1854 | + | |
1855 | + $this->parent->_[HDOM_INFO_END] = $this->cursor; | |
1856 | + return $this->as_text_node($tag); | |
1857 | + } | |
1858 | + } elseif (($this->parent->parent) | |
1859 | + && isset($this->block_tags[$tag_lower]) | |
1860 | + ) { | |
1861 | + // Grandparent exists and current tag is a block tag, so our | |
1862 | + // parent doesn't have an end tag | |
1863 | + $this->parent->_[HDOM_INFO_END] = 0; // No end tag | |
1864 | + $org_parent = $this->parent; | |
1865 | + | |
1866 | + // Traverse ancestors to find a matching opening tag | |
1867 | + // Stop at root node | |
1868 | + while (($this->parent->parent) | |
1869 | + && strtolower($this->parent->tag) !== $tag_lower | |
1870 | + ) { | |
1871 | + $this->parent = $this->parent->parent; | |
1872 | + } | |
1873 | + | |
1874 | + // If we don't have a match add current tag as text node | |
1875 | + if (strtolower($this->parent->tag) !== $tag_lower) { | |
1876 | + $this->parent = $org_parent; // restore origonal parent | |
1877 | + $this->parent->_[HDOM_INFO_END] = $this->cursor; | |
1878 | + return $this->as_text_node($tag); | |
1879 | + } | |
1880 | + } elseif (($this->parent->parent) | |
1881 | + && strtolower($this->parent->parent->tag) === $tag_lower | |
1882 | + ) { // Grandparent exists and current tag closes it | |
1883 | + $this->parent->_[HDOM_INFO_END] = 0; | |
1884 | + $this->parent = $this->parent->parent; | |
1885 | + } else { // Random tag, add as text node | |
1886 | + return $this->as_text_node($tag); | |
1887 | + } | |
1888 | + } | |
1889 | + | |
1890 | + // Set end position of parent tag to current cursor position | |
1891 | + $this->parent->_[HDOM_INFO_END] = $this->cursor; | |
1892 | + | |
1893 | + if ($this->parent->parent) { | |
1894 | + $this->parent = $this->parent->parent; | |
1895 | + } | |
1896 | + | |
1897 | + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next | |
1898 | + return true; | |
1899 | + } | |
1900 | + | |
1901 | + // start tag | |
1902 | + $node = new simple_html_dom_node($this); | |
1903 | + $node->_[HDOM_INFO_BEGIN] = $this->cursor; | |
1904 | + ++$this->cursor; | |
1905 | + $tag = $this->copy_until($this->token_slash); // Get tag name | |
1906 | + $node->tag_start = $begin_tag_pos; | |
1907 | + | |
1908 | + // doctype, cdata & comments... | |
1909 | + // <!DOCTYPE html> | |
1910 | + // <![CDATA[ ... ]]> | |
1911 | + // <!-- Comment --> | |
1912 | + if (isset($tag[0]) && $tag[0] === '!') { | |
1913 | + $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until_char('>'); | |
1914 | + | |
1915 | + if (isset($tag[2]) && $tag[1] === '-' && $tag[2] === '-') { // Comment ("<!--") | |
1916 | + $node->nodetype = HDOM_TYPE_COMMENT; | |
1917 | + $node->tag = 'comment'; | |
1918 | + } else { // Could be doctype or CDATA but we don't care | |
1919 | + $node->nodetype = HDOM_TYPE_UNKNOWN; | |
1920 | + $node->tag = 'unknown'; | |
1921 | + } | |
1922 | + | |
1923 | + if ($this->char === '>') { $node->_[HDOM_INFO_TEXT] .= '>'; } | |
1924 | + | |
1925 | + $this->link_nodes($node, true); | |
1926 | + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next | |
1927 | + return true; | |
1928 | + } | |
1929 | + | |
1930 | + // The start tag cannot contain another start tag, if so add as text | |
1931 | + // i.e. "<<html>" | |
1932 | + if ($pos = strpos($tag, '<') !== false) { | |
1933 | + $tag = '<' . substr($tag, 0, -1); | |
1934 | + $node->_[HDOM_INFO_TEXT] = $tag; | |
1935 | + $this->link_nodes($node, false); | |
1936 | + $this->char = $this->doc[--$this->pos]; // prev | |
1937 | + return true; | |
1938 | + } | |
1939 | + | |
1940 | + // Handle invalid tag names (i.e. "<html#doc>") | |
1941 | + if (!preg_match('/^\w[\w:-]*$/', $tag)) { | |
1942 | + $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until('<>'); | |
1943 | + | |
1944 | + // Next char is the beginning of a new tag, don't touch it. | |
1945 | + if ($this->char === '<') { | |
1946 | + $this->link_nodes($node, false); | |
1947 | + return true; | |
1948 | + } | |
1949 | + | |
1950 | + // Next char closes current tag, add and be done with it. | |
1951 | + if ($this->char === '>') { $node->_[HDOM_INFO_TEXT] .= '>'; } | |
1952 | + $this->link_nodes($node, false); | |
1953 | + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next | |
1954 | + return true; | |
1955 | + } | |
1956 | + | |
1957 | + // begin tag, add new node | |
1958 | + $node->nodetype = HDOM_TYPE_ELEMENT; | |
1959 | + $tag_lower = strtolower($tag); | |
1960 | + $node->tag = ($this->lowercase) ? $tag_lower : $tag; | |
1961 | + | |
1962 | + // handle optional closing tags | |
1963 | + if (isset($this->optional_closing_tags[$tag_lower])) { | |
1964 | + // Traverse ancestors to close all optional closing tags | |
1965 | + while (isset($this->optional_closing_tags[$tag_lower][strtolower($this->parent->tag)])) { | |
1966 | + $this->parent->_[HDOM_INFO_END] = 0; | |
1967 | + $this->parent = $this->parent->parent; | |
1968 | + } | |
1969 | + $node->parent = $this->parent; | |
1970 | + } | |
1971 | + | |
1972 | + $guard = 0; // prevent infinity loop | |
1973 | + | |
1974 | + // [0] Space between tag and first attribute | |
1975 | + $space = array($this->copy_skip($this->token_blank), '', ''); | |
1976 | + | |
1977 | + // attributes | |
1978 | + do { | |
1979 | + // Everything until the first equal sign should be the attribute name | |
1980 | + $name = $this->copy_until($this->token_equal); | |
1981 | + | |
1982 | + if ($name === '' && $this->char !== null && $space[0] === '') { | |
1983 | + break; | |
1984 | + } | |
1985 | + | |
1986 | + if ($guard === $this->pos) { // Escape infinite loop | |
1987 | + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next | |
1988 | + continue; | |
1989 | + } | |
1990 | + | |
1991 | + $guard = $this->pos; | |
1992 | + | |
1993 | + // handle endless '<' | |
1994 | + // Out of bounds before the tag ended | |
1995 | + if ($this->pos >= $this->size - 1 && $this->char !== '>') { | |
1996 | + $node->nodetype = HDOM_TYPE_TEXT; | |
1997 | + $node->_[HDOM_INFO_END] = 0; | |
1998 | + $node->_[HDOM_INFO_TEXT] = '<' . $tag . $space[0] . $name; | |
1999 | + $node->tag = 'text'; | |
2000 | + $this->link_nodes($node, false); | |
2001 | + return true; | |
2002 | + } | |
2003 | + | |
2004 | + // handle mismatch '<' | |
2005 | + // Attributes cannot start after opening tag | |
2006 | + if ($this->doc[$this->pos - 1] == '<') { | |
2007 | + $node->nodetype = HDOM_TYPE_TEXT; | |
2008 | + $node->tag = 'text'; | |
2009 | + $node->attr = array(); | |
2010 | + $node->_[HDOM_INFO_END] = 0; | |
2011 | + $node->_[HDOM_INFO_TEXT] = substr( | |
2012 | + $this->doc, | |
2013 | + $begin_tag_pos, | |
2014 | + $this->pos - $begin_tag_pos - 1 | |
2015 | + ); | |
2016 | + $this->pos -= 2; | |
2017 | + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next | |
2018 | + $this->link_nodes($node, false); | |
2019 | + return true; | |
2020 | + } | |
2021 | + | |
2022 | + if ($name !== '/' && $name !== '') { // this is a attribute name | |
2023 | + // [1] Whitespace after attribute name | |
2024 | + $space[1] = $this->copy_skip($this->token_blank); | |
2025 | + | |
2026 | + $name = $this->restore_noise($name); // might be a noisy name | |
2027 | + | |
2028 | + if ($this->lowercase) { $name = strtolower($name); } | |
2029 | + | |
2030 | + if ($this->char === '=') { // attribute with value | |
2031 | + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next | |
2032 | + $this->parse_attr($node, $name, $space); // get attribute value | |
2033 | + } else { | |
2034 | + //no value attr: nowrap, checked selected... | |
2035 | + $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_NO; | |
2036 | + $node->attr[$name] = true; | |
2037 | + if ($this->char != '>') { $this->char = $this->doc[--$this->pos]; } // prev | |
2038 | + } | |
2039 | + | |
2040 | + $node->_[HDOM_INFO_SPACE][] = $space; | |
2041 | + | |
2042 | + // prepare for next attribute | |
2043 | + $space = array( | |
2044 | + $this->copy_skip($this->token_blank), | |
2045 | + '', | |
2046 | + '' | |
2047 | + ); | |
2048 | + } else { // no more attributes | |
2049 | + break; | |
2050 | + } | |
2051 | + } while ($this->char !== '>' && $this->char !== '/'); // go until the tag ended | |
2052 | + | |
2053 | + $this->link_nodes($node, true); | |
2054 | + $node->_[HDOM_INFO_ENDSPACE] = $space[0]; | |
2055 | + | |
2056 | + // handle empty tags (i.e. "<div/>") | |
2057 | + if ($this->copy_until_char('>') === '/') { | |
2058 | + $node->_[HDOM_INFO_ENDSPACE] .= '/'; | |
2059 | + $node->_[HDOM_INFO_END] = 0; | |
2060 | + } else { | |
2061 | + // reset parent | |
2062 | + if (!isset($this->self_closing_tags[strtolower($node->tag)])) { | |
2063 | + $this->parent = $node; | |
2064 | + } | |
2065 | + } | |
2066 | + | |
2067 | + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next | |
2068 | + | |
2069 | + // If it's a BR tag, we need to set it's text to the default text. | |
2070 | + // This way when we see it in plaintext, we can generate formatting that the user wants. | |
2071 | + // since a br tag never has sub nodes, this works well. | |
2072 | + if ($node->tag === 'br') { | |
2073 | + $node->_[HDOM_INFO_INNER] = $this->default_br_text; | |
2074 | + } | |
2075 | + | |
2076 | + return true; | |
2077 | + } | |
2078 | + | |
2079 | + protected function parse_attr($node, $name, &$space) | |
2080 | + { | |
2081 | + $is_duplicate = isset($node->attr[$name]); | |
2082 | + | |
2083 | + if (!$is_duplicate) // Copy whitespace between "=" and value | |
2084 | + $space[2] = $this->copy_skip($this->token_blank); | |
2085 | + | |
2086 | + switch ($this->char) { | |
2087 | + case '"': | |
2088 | + $quote_type = HDOM_QUOTE_DOUBLE; | |
2089 | + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next | |
2090 | + $value = $this->copy_until_char('"'); | |
2091 | + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next | |
2092 | + break; | |
2093 | + case '\'': | |
2094 | + $quote_type = HDOM_QUOTE_SINGLE; | |
2095 | + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next | |
2096 | + $value = $this->copy_until_char('\''); | |
2097 | + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next | |
2098 | + break; | |
2099 | + default: | |
2100 | + $quote_type = HDOM_QUOTE_NO; | |
2101 | + $value = $this->copy_until($this->token_attr); | |
2102 | + } | |
2103 | + | |
2104 | + $value = $this->restore_noise($value); | |
2105 | + | |
2106 | + // PaperG: Attributes should not have \r or \n in them, that counts as | |
2107 | + // html whitespace. | |
2108 | + $value = str_replace("\r", '', $value); | |
2109 | + $value = str_replace("\n", '', $value); | |
2110 | + | |
2111 | + // PaperG: If this is a "class" selector, lets get rid of the preceeding | |
2112 | + // and trailing space since some people leave it in the multi class case. | |
2113 | + if ($name === 'class') { | |
2114 | + $value = trim($value); | |
2115 | + } | |
2116 | + | |
2117 | + if (!$is_duplicate) { | |
2118 | + $node->_[HDOM_INFO_QUOTE][] = $quote_type; | |
2119 | + $node->attr[$name] = $value; | |
2120 | + } | |
2121 | + } | |
2122 | + | |
2123 | + protected function link_nodes(&$node, $is_child) | |
2124 | + { | |
2125 | + $node->parent = $this->parent; | |
2126 | + $this->parent->nodes[] = $node; | |
2127 | + if ($is_child) { | |
2128 | + $this->parent->children[] = $node; | |
2129 | + } | |
2130 | + } | |
2131 | + | |
2132 | + protected function as_text_node($tag) | |
2133 | + { | |
2134 | + $node = new simple_html_dom_node($this); | |
2135 | + ++$this->cursor; | |
2136 | + $node->_[HDOM_INFO_TEXT] = '</' . $tag . '>'; | |
2137 | + $this->link_nodes($node, false); | |
2138 | + $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; // next | |
2139 | + return true; | |
2140 | + } | |
2141 | + | |
2142 | + protected function skip($chars) | |
2143 | + { | |
2144 | + $this->pos += strspn($this->doc, $chars, $this->pos); | |
2145 | + $this->char = ($this->pos < $this->size) ? $this->doc[$this->pos] : null; // next | |
2146 | + } | |
2147 | + | |
2148 | + protected function copy_skip($chars) | |
2149 | + { | |
2150 | + $pos = $this->pos; | |
2151 | + $len = strspn($this->doc, $chars, $pos); | |
2152 | + $this->pos += $len; | |
2153 | + $this->char = ($this->pos < $this->size) ? $this->doc[$this->pos] : null; // next | |
2154 | + if ($len === 0) { return ''; } | |
2155 | + return substr($this->doc, $pos, $len); | |
2156 | + } | |
2157 | + | |
2158 | + protected function copy_until($chars) | |
2159 | + { | |
2160 | + $pos = $this->pos; | |
2161 | + $len = strcspn($this->doc, $chars, $pos); | |
2162 | + $this->pos += $len; | |
2163 | + $this->char = ($this->pos < $this->size) ? $this->doc[$this->pos] : null; // next | |
2164 | + return substr($this->doc, $pos, $len); | |
2165 | + } | |
2166 | + | |
2167 | + protected function copy_until_char($char) | |
2168 | + { | |
2169 | + if ($this->char === null) { return ''; } | |
2170 | + | |
2171 | + if (($pos = strpos($this->doc, $char, $this->pos)) === false) { | |
2172 | + $ret = substr($this->doc, $this->pos, $this->size - $this->pos); | |
2173 | + $this->char = null; | |
2174 | + $this->pos = $this->size; | |
2175 | + return $ret; | |
2176 | + } | |
2177 | + | |
2178 | + if ($pos === $this->pos) { return ''; } | |
2179 | + | |
2180 | + $pos_old = $this->pos; | |
2181 | + $this->char = $this->doc[$pos]; | |
2182 | + $this->pos = $pos; | |
2183 | + return substr($this->doc, $pos_old, $pos - $pos_old); | |
2184 | + } | |
2185 | + | |
2186 | + protected function remove_noise($pattern, $remove_tag = false) | |
2187 | + { | |
2188 | + global $debug_object; | |
2189 | + if (is_object($debug_object)) { $debug_object->debug_log_entry(1); } | |
2190 | + | |
2191 | + $count = preg_match_all( | |
2192 | + $pattern, | |
2193 | + $this->doc, | |
2194 | + $matches, | |
2195 | + PREG_SET_ORDER | PREG_OFFSET_CAPTURE | |
2196 | + ); | |
2197 | + | |
2198 | + for ($i = $count - 1; $i > -1; --$i) { | |
2199 | + $key = '___noise___' . sprintf('% 5d', count($this->noise) + 1000); | |
2200 | + | |
2201 | + if (is_object($debug_object)) { | |
2202 | + $debug_object->debug_log(2, 'key is: ' . $key); | |
2203 | + } | |
2204 | + | |
2205 | + $idx = ($remove_tag) ? 0 : 1; // 0 = entire match, 1 = submatch | |
2206 | + $this->noise[$key] = $matches[$i][$idx][0]; | |
2207 | + $this->doc = substr_replace($this->doc, $key, $matches[$i][$idx][1], strlen($matches[$i][$idx][0])); | |
2208 | + } | |
2209 | + | |
2210 | + // reset the length of content | |
2211 | + $this->size = strlen($this->doc); | |
2212 | + | |
2213 | + if ($this->size > 0) { | |
2214 | + $this->char = $this->doc[0]; | |
2215 | + } | |
2216 | + } | |
2217 | + | |
2218 | + function restore_noise($text) | |
2219 | + { | |
2220 | + global $debug_object; | |
2221 | + if (is_object($debug_object)) { $debug_object->debug_log_entry(1); } | |
2222 | + | |
2223 | + while (($pos = strpos($text, '___noise___')) !== false) { | |
2224 | + // Sometimes there is a broken piece of markup, and we don't GET the | |
2225 | + // pos+11 etc... token which indicates a problem outside of us... | |
2226 | + | |
2227 | + // todo: "___noise___1000" (or any number with four or more digits) | |
2228 | + // in the DOM causes an infinite loop which could be utilized by | |
2229 | + // malicious software | |
2230 | + if (strlen($text) > $pos + 15) { | |
2231 | + $key = '___noise___' | |
2232 | + . $text[$pos + 11] | |
2233 | + . $text[$pos + 12] | |
2234 | + . $text[$pos + 13] | |
2235 | + . $text[$pos + 14] | |
2236 | + . $text[$pos + 15]; | |
2237 | + | |
2238 | + if (is_object($debug_object)) { | |
2239 | + $debug_object->debug_log(2, 'located key of: ' . $key); | |
2240 | + } | |
2241 | + | |
2242 | + if (isset($this->noise[$key])) { | |
2243 | + $text = substr($text, 0, $pos) | |
2244 | + . $this->noise[$key] | |
2245 | + . substr($text, $pos + 16); | |
2246 | + } else { | |
2247 | + // do this to prevent an infinite loop. | |
2248 | + $text = substr($text, 0, $pos) | |
2249 | + . 'UNDEFINED NOISE FOR KEY: ' | |
2250 | + . $key | |
2251 | + . substr($text, $pos + 16); | |
2252 | + } | |
2253 | + } else { | |
2254 | + // There is no valid key being given back to us... We must get | |
2255 | + // rid of the ___noise___ or we will have a problem. | |
2256 | + $text = substr($text, 0, $pos) | |
2257 | + . 'NO NUMERIC NOISE KEY' | |
2258 | + . substr($text, $pos + 11); | |
2259 | + } | |
2260 | + } | |
2261 | + return $text; | |
2262 | + } | |
2263 | + | |
2264 | + function search_noise($text) | |
2265 | + { | |
2266 | + global $debug_object; | |
2267 | + if (is_object($debug_object)) { $debug_object->debug_log_entry(1); } | |
2268 | + | |
2269 | + foreach($this->noise as $noiseElement) { | |
2270 | + if (strpos($noiseElement, $text) !== false) { | |
2271 | + return $noiseElement; | |
2272 | + } | |
2273 | + } | |
2274 | + } | |
2275 | + | |
2276 | + function __toString() | |
2277 | + { | |
2278 | + return $this->root->innertext(); | |
2279 | + } | |
2280 | + | |
2281 | + function __get($name) | |
2282 | + { | |
2283 | + switch ($name) { | |
2284 | + case 'outertext': | |
2285 | + return $this->root->innertext(); | |
2286 | + case 'innertext': | |
2287 | + return $this->root->innertext(); | |
2288 | + case 'plaintext': | |
2289 | + return $this->root->text(); | |
2290 | + case 'charset': | |
2291 | + return $this->_charset; | |
2292 | + case 'target_charset': | |
2293 | + return $this->_target_charset; | |
2294 | + } | |
2295 | + } | |
2296 | + | |
2297 | + function childNodes($idx = -1) | |
2298 | + { | |
2299 | + return $this->root->childNodes($idx); | |
2300 | + } | |
2301 | + | |
2302 | + function firstChild() | |
2303 | + { | |
2304 | + return $this->root->first_child(); | |
2305 | + } | |
2306 | + | |
2307 | + function lastChild() | |
2308 | + { | |
2309 | + return $this->root->last_child(); | |
2310 | + } | |
2311 | + | |
2312 | + function createElement($name, $value = null) | |
2313 | + { | |
2314 | + return @str_get_html("<$name>$value</$name>")->firstChild(); | |
2315 | + } | |
2316 | + | |
2317 | + function createTextNode($value) | |
2318 | + { | |
2319 | + return @end(str_get_html($value)->nodes); | |
2320 | + } | |
2321 | + | |
2322 | + function getElementById($id) | |
2323 | + { | |
2324 | + return $this->find("#$id", 0); | |
2325 | + } | |
2326 | + | |
2327 | + function getElementsById($id, $idx = null) | |
2328 | + { | |
2329 | + return $this->find("#$id", $idx); | |
2330 | + } | |
2331 | + | |
2332 | + function getElementByTagName($name) | |
2333 | + { | |
2334 | + return $this->find($name, 0); | |
2335 | + } | |
2336 | + | |
2337 | + function getElementsByTagName($name, $idx = -1) | |
2338 | + { | |
2339 | + return $this->find($name, $idx); | |
2340 | + } | |
2341 | + | |
2342 | + function loadFile() | |
2343 | + { | |
2344 | + $args = func_get_args(); | |
2345 | + $this->load_file($args); | |
2346 | + } | |
2347 | +} | |
... | ... |
php/config.php
... | ... | @@ -183,7 +183,7 @@ $API = array( |
183 | 183 | //AKKA - New action to clean user WS |
184 | 184 | 'cleanUserWS'=>array('len'=>0), |
185 | 185 | 'deleteSpecialInfo'=>array('len'=>1), |
186 | - 'interactivePlot'=>array('len'=>2), | |
186 | + 'interactivePlot'=>array('len'=>1), | |
187 | 187 | 'getParamPlotInit'=>array('len'=>1), |
188 | 188 | 'getParamInfo'=>array('len'=>1), |
189 | 189 | 'getDerivedParamInfo'=>array('len'=>1), |
... | ... |
php/downloadPlot.php
... | ... | @@ -10,19 +10,19 @@ if (!isset($_POST['sessionId'])) |
10 | 10 | } |
11 | 11 | $sessionId = $_POST['sessionId']; |
12 | 12 | |
13 | -if (!isset($_POST['tabId'])) | |
13 | +if (!isset($_POST['interactiveId'])) | |
14 | 14 | { |
15 | 15 | header("HTTP/1.0 400 Bad Request"); |
16 | - echo json_encode(array("success" => false, "error" => "Unknown tab Id")); | |
16 | + echo json_encode(array("success" => false, "error" => "Unknown interactive Id")); | |
17 | 17 | exit; |
18 | 18 | } |
19 | -$tabId = $_POST['tabId']; | |
19 | +$interactiveId = $_POST['interactiveId']; | |
20 | 20 | |
21 | 21 | $preview = empty($_POST['preview']) ? FALSE : $_POST['preview']; |
22 | 22 | |
23 | -download_plot($sessionId, $tabId, $preview); | |
23 | +download_plot($sessionId, $interactiveId, $preview); | |
24 | 24 | |
25 | -function download_plot($sessionId, $tabId, $preview) | |
25 | +function download_plot($sessionId, $interactiveId, $preview) | |
26 | 26 | { |
27 | 27 | // Must be fresh start |
28 | 28 | if( headers_sent() ) |
... | ... | @@ -38,10 +38,10 @@ function download_plot($sessionId, $tabId, $preview) |
38 | 38 | |
39 | 39 | //Build file path |
40 | 40 | if (!$preview) { |
41 | - $fullPath = USERPATH."/".$sessionId."/RES/Plot_/".$tabId.".png"; | |
41 | + $fullPath = USERPATH."/".$sessionId."/RES/Plot_/".$interactiveId.".png"; | |
42 | 42 | } |
43 | 43 | else { |
44 | - $fullPath = USERPATH."/".$sessionId."/RES/Plot_/".str_replace('plot_','instant',$tabId).".png"; | |
44 | + $fullPath = USERPATH."/".$sessionId."/RES/Plot_/".str_replace('plot_','instant',$interactiveId).".png"; | |
45 | 45 | } |
46 | 46 | // File Exists? |
47 | 47 | if( file_exists($fullPath) ){ |
... | ... |
php/src/cdfsamplingfromdata.c
... | ... | @@ -126,7 +126,7 @@ int main(int argc, char *argv[]) |
126 | 126 | if (datatype == CDF_TIME_TT2000) { |
127 | 127 | dbl_value_ = CDF_TT2000_to_UTC_EPOCH(int_value[0]); |
128 | 128 | dbl_value = CDF_TT2000_to_UTC_EPOCH(int_value[1]); |
129 | - sampling = (int)(dbl_value - dbl_value_ + 50)/100; | |
129 | + sampling = (int)(dbl_value - dbl_value_); | |
130 | 130 | } |
131 | 131 | else { |
132 | 132 | if (datatype == CDF_EPOCH16) { |
... | ... | @@ -139,7 +139,7 @@ int main(int argc, char *argv[]) |
139 | 139 | EPOCH16breakdown(epoch16, &year, &month, &day, &hour, &minute, &sec, &msec, &mksec, &nsec, &psec); |
140 | 140 | value[1] = computeEPOCH(year, month, day, hour, minute, sec, msec); |
141 | 141 | } |
142 | - sampling = (int)(value[1] - value[0] + 50)/100; | |
142 | + sampling = (int)(value[1] - value[0]); | |
143 | 143 | } |
144 | 144 | |
145 | 145 | // fprintf(stdout,"value %f\n", value[11]-value[10]); |
... | ... | @@ -150,5 +150,5 @@ int main(int argc, char *argv[]) |
150 | 150 | if ((cstatus = CDFlib(CLOSE_, CDF_, NULL_)) != CDF_OK) |
151 | 151 | cdf_handle_error (cstatus); |
152 | 152 | |
153 | - fprintf(stdout,"%f\n",(float)sampling/10.0); | |
153 | + fprintf(stdout,"%f\n",(float)sampling/1000.0); // in sec.msec | |
154 | 154 | } |
... | ... |
php/src/cdfsamplingsfromdata.c
... | ... | @@ -162,7 +162,7 @@ int main(int argc, char *argv[]) |
162 | 162 | if (datatype == CDF_TIME_TT2000) { |
163 | 163 | dbl_value_ = CDF_TT2000_to_UTC_EPOCH(int_value[i-1]); |
164 | 164 | dbl_value = CDF_TT2000_to_UTC_EPOCH(int_value[i]); |
165 | - delta[i-1] = (int)(dbl_value - dbl_value_ + 50)/100; | |
165 | + delta[i-1] = (int)(dbl_value - dbl_value_); | |
166 | 166 | } |
167 | 167 | else { |
168 | 168 | if (datatype == CDF_EPOCH16) { |
... | ... | @@ -175,7 +175,7 @@ int main(int argc, char *argv[]) |
175 | 175 | EPOCH16breakdown(epoch16, &year, &month, &day, &hour, &minute, &sec, &msec, &mksec, &nsec, &psec); |
176 | 176 | value[i] = computeEPOCH(year, month, day, hour, minute, sec, msec); |
177 | 177 | } |
178 | - delta[i-1] = (int)(value[i] - value[i-1] + 50)/100; | |
178 | + delta[i-1] = (int)(value[i] - value[i-1]); | |
179 | 179 | } |
180 | 180 | } |
181 | 181 | // fprintf(stdout,"value %f\n", value[11]-value[10]); |
... | ... | @@ -194,5 +194,5 @@ int main(int argc, char *argv[]) |
194 | 194 | cdf_handle_error (cstatus); |
195 | 195 | |
196 | 196 | // fprintf(stdout,"%d %f\n",min[1], (float)min[0]/100.0); |
197 | - fprintf(stdout,"%f\n",(float)min[0]/10.0); | |
197 | + fprintf(stdout,"%f\n",(float)min[0]/1000.0); | |
198 | 198 | } |
... | ... |