1const urlPath = window.location.pathname.match(/\/.*\//) || '/'; // need only the path without trailing file names 2 3const vm = new Vue({ 4 el: "#vue-instance", 5 data() { 6 return { 7 // can set default values here 8 //baseUrl: `//${window.location.hostname}:3000`, // LOCAL MAC API url 9 //baseUrl: 'https://legislature.maine.gov/mrs-search/api', // frontend only, public only testing 10 baseUrl: `//${window.location.host}${urlPath}api`, // API url 11 //apiUrl: 'https://legislature.maine.gov/api', // frontend only testing 12 //apiUrl: `//${window.location.hostname}:5000`, // LOCAL testing 13 apiUrl: `//${window.location.hostname}/api`, //DEPLOYED URL 14 searchTerm: "", // Default search term 15 title: "", 16 ldNumberLow: null, 17 ldNumberHigh: null, 18 legislature: null, 19 paperNumberType: null, 20 paperNumberLow: null, 21 paperNumberHigh: null, 22 requestItemType: null, 23 summary: null, 24 // lawmaker and LEAP search items from form 25 lmSponsor: null, 26 lmSponsorPrimary: false, 27 lmIntroducer: null, 28 lmRollCallBody: null, 29 lmRollCallNumber: null, 30 lmRollCallStartDate: null, 31 lmRollCallEndDate: null, 32 reqHouseAction: null, 33 reqSenateAction: null, 34 reqAmendBody: null, 35 reqAmendFiling: null, 36 reqSeqBody1: null, 37 reqSeqBody2: null, 38 reqAmendSeq1: null, 39 reqAmendSeq2: null, 40 reqAmendExists: false, 41 reqAmendAdoptH: false, 42 reqAmendAdoptS: false, 43 reqLawType: null, 44 reqChapter: null, 45 reqChapterExists: false, 46 reqCommittee: null, 47 reqCommitteeAction: null, 48 reqPublicHearingStartDate: null, 49 reqPublicHearingEndDate: null, 50 reqWorkSessionStartDate: null, 51 reqWorkSessionEndDate: null, 52 reqTestimonyStartDate: null, 53 reqTestimonyEndDate: null, 54 reqTestimonyNameFirst: null, 55 reqTestimonyNameLast: null, 56 reqFinalDisposition: null, 57 reqFinalDispositionActionId: null, 58 reqGovernorAction: null, 59 reqTSTitle: null, 60 reqTSSection: null, 61 reqTSSubsection: null, 62 reqTSParagraph: null, 63 reqFiscalImpact: null, 64 reqFNRequired: false, 65 reqEmergency: false, 66 reqGovernor: false, 67 reqBond: false, 68 reqMandate: false, 69 reqPublicLand: false, 70 // end lawmaker/leap 71 showExtraParameters: false, 72 mustHave: "", // filters - must have these exactly? 73 mustNotHave: "", // filters - results not have these 74 searchOffset: 0, // Search result pagination offset 75 pageSize: 12, 76 sortByScore: false, 77 showBillText: false, 78 sortAscending: false, 79 excludeOrders: false, 80 listAllResults: false, // change page size to be equal to number of hits, up to pageMaxLimit below. 81 searchDebounce: null, // Timeout for search bar debounce 82 searchResults: [], // Displayed search results 83 numHits: null, // Total search results found 84 pageMaxLimit: 500, // maximum page size 85 pageMinLimit: 10, // minimum page size - could probably be smaller, but at some point why would you bother 86 displayPageCount: 0, // actual number of results on the page - sometimes less than pagesize if separateSections is false 87 displayOffset: 0, //display offset that takes into account the results of the separateSections consolidation 88 showInstructions: false, // show instructions on search page 89 timestamp: null, 90 committeeActions: [], 91 floorActions:[], 92 governorActions: [], 93 finalActions: [], 94 committees: [], 95 sponsors: [], 96 legislatures: [], 97 err: null 98 }; 99 }, 100 async created() { 101 axios.get(`${this.apiUrl}/QRY-LEG-LST`) 102 .then(legList => { 103 this.legislatures = legList.data; 104 }) 105 .catch(err => { 106 console.log(`Error fetching legislature list - ${JSON.stringify(err)}`); 107 }); 108 axios.get(`${this.apiUrl}/QRY-CUR-LEG`) 109 .then(currentLeg => { 110 this.legislature = currentLeg.data; 111 this.getMetadata(this.legislature); 112 this.search() 113 .then(results => { 114 this.searchResults = results; 115 }) 116 .catch(err => { 117 console.log(`Error fetching default search - ${JSON.stringify(err)}`); 118 }); 119 }) 120 .catch(err => { 121 console.log(`Error fetching current Legislature - ${JSON.stringify(err)}`); 122 }); 123 124 // retrieve Action tables - no parameters! 125 axios.get(`${this.apiUrl}/QRY-META-ACTION`) 126 .then(response => { 127 this.committeeActions = response.data.COM; 128 this.floorActions = response.data.FLR; 129 this.governorActions = response.data.GOV; 130 this.finalActions = response.data.FD; 131 //console.log(`response: ${JSON.stringify(response)}`) 132 console.log(`found action metadata, status ${response.status}`) 133 }) 134 .catch(err => { 135 console.log(`Error fetching action metadata - ${JSON.stringify(err)}`); 136 }); 137 //this.searchResults = await this.search(); // Search for default term 138 }, 139 computed:{ 140 }, 141 methods: { 142 /** Debounce search input by ms */ 143 onSearchInput() { 144 clearTimeout(this.searchDebounce); 145 this.searchDebounce = setTimeout(async () => { 146 this.searchOffset = 0; 147 this.displayOffset = 0; 148 this.getMetadata(this.legislature); 149 this.searchResults = await this.search(); 150 }, 500); 151 }, 152 getNow: function () { //Date time US style 153 const today = new Date(); 154 const todayDate = (today.getMonth() + 1) + '/' + today.getDate() + '/' + today.getFullYear(); 155 const todayTime = today.getHours() + ":" + new String("00" + today.getMinutes()).slice(-2); 156 this.timestamp = todayDate + ' ' + todayTime; 157 }, 158 159 toggleInstructionDisplay() { 160 this.showInstructions = !this.showInstructions; 161 }, 162 toggleParameterDisplay() { 163 this.showExtraParameters = !this.showExtraParameters; 164 }, 165 setListFormat(val) { 166 this.listAllResults = (val == 1) ? true: false;
167 }, 168 cmteLegislatureRange: function(from, to) { 169 return !this.legislature ? `${this.ordinal(from)} - ${this.ordinal(to)}` : ''; 170 }, 171 resetPage: function() { 172 window.location.reload(); 173 }, 174 ordinal(number) { 175 if (isNaN(parseInt(number,10))) return ''; 176 177 if (number % 100 > 9 && number % 100 < 21 ) return number + 'th'; 178 switch (number % 10) { 179 case 1: 180 return number + 'st'; 181 case 2: 182 return number + 'nd'; 183 case 3: 184 return number + 'rd'; 185 default: 186 return number + 'th'; 187 } 188 }, 189 itemTypeDisplay(requestItemType) { 190 return (({ 191 'O': ' ', //Original 192 'A': ', Amendment ', 193 'K': ', Concept Draft ', //Concept Draft 194 'C': ', ', // was "Chaptered Law " but phrase not needed with law type and chapter number 195 'E': ' ', //Engrosser 196 'N': ' ', //New Draft 197 'W': ' ', //Working Draft 198 'F': ' ', //Fiscal Working Draft 199 'JR': ', Joint Resolution ', 200 'ES': ', Summary ' //Enacted Law Summary - don't think we have any of these. 201 })[requestItemType] ?? ''); 202 }, 203 lawTypeDisplay(lawType){ 204 return (({ 205 "ACTPUB": 'Public Law', 206 "ACTPS": 'Private & Special', 207 "CONRES": 'Constitutional Resolution', 208 "RESLV": 'Resolve', 209 "IB": 'Initiated Bill', 210 "JSO": 'Joint Study Order', 211 "JTRES": 'Joint Resolution', 212 "CMR": 'Competing Mesure Resolution', 213 })[lawType] ?? ''); 214 }, 215 billStatusUrl(legislature, paperNumber) { 216 return (`https://legislature.maine.gov/billtracker/#Paper/${paperNumber}?legislature=${legislature}`); 217 }, 218 219 /** Call API to search */ 220 async search() { 221 this.getNow(); //update time on each search 222 if (isNaN(parseInt(this.pageSize, 10))) { return; } // do this first to prevent NaN from appearing if user deletes entire number 223 this.pageSize = parseInt(this.pageSize, 10); 224 if (this.pageSize > this.pageMaxLimit) { this.pageSize = this.pageMaxLimit } 225 if (this.pageSize < this.pageMinLimit) { this.pageSize = this.pageMinLimit } 226 let response = null; 227 try { 228 this.err = null; 229 response = await axios.get(`${this.baseUrl}/billtext`, { 230 params: { 231 term: this.searchTerm, 232 title: this.title, 233 ldNumberLow: this.ldNumberLow, 234 ldNumberHigh: this.ldNumberHigh, 235 legislature: this.legislature, 236 paperNumberType: this.paperNumberType, 237 paperNumberLow: this.paperNumberLow, 238 paperNumberHigh: this.paperNumberHigh, 239 requestItemType: this.requestItemType, 240 summary: this.summary, 241 // lawmaker and LEAP search items from form 242 lmSponsor: this.lmSponsor, 243 lmSponsorPrimary: this.lmSponsorPrimary, 244 lmIntroducer: this.lmIntroducer, 245 lmRollCallBody: this.lmRollCallBody, 246 lmRollCallNumber: this.lmRollCallNumber, 247 lmRollCallStartDate: this.lmRollCallStartDate, 248 lmRollCallEndDate: this.lmRollCallEndDate, 249 reqHouseAction: this.reqHouseAction, 250 reqSenateAction: this.reqSenateAction, 251 reqAmendBody: this.reqAmendBody, 252 reqAmendFiling: this.reqAmendFiling, 253 reqSeqBody1: this.reqSeqBody1, 254 reqSeqBody2: this.reqSeqBody2, 255 reqAmendSeq1: this.reqAmendSeq1, 256 reqAmendSeq2: this.reqAmendSeq2, 257 reqAmendExists: this.reqAmendExists, 258 reqAmendAdoptH: this.reqAmendAdoptH, 259 reqAmendAdoptS: this.reqAmendAdoptS, 260 reqLawType: this.reqLawType, 261 reqChapter: this.reqChapter, 262 reqChapterExists: this.reqChapterExists, 263 reqCommittee: this.reqCommittee, 264 reqCommitteeAction: this.reqCommitteeAction, 265 reqPublicHearingStartDate: this.reqPublicHearingStartDate, 266 reqPublicHearingEndDate: this.reqPublicHearingEndDate, 267 reqWorkSessionStartDate: this.reqWorkSessionStartDate, 268 reqWorkSessionEndDate: this.reqWorkSessionEndDate, 269 reqTestimonyStartDate: this.reqTestimonyStartDate, 270 reqTestimonyEndDate: this.reqTestimonyEndDate, 271 reqTestimonyNameFirst: this.reqTestimonyNameFirst, 272 reqTestimonyNameLast: this.reqTestimonyNameLast, 273 reqFinalDisposition: this.reqFinalDisposition, 274 reqFinalDispositionActionId: this.reqFinalDispositionActionId, 275 reqGovernorAction: this.reqGovernorAction, 276 reqTSTitle: this.reqTSTitle, 277 reqTSSection: this.reqTSSection, 278 reqTSSubsection: this.reqTSSubsection, 279 reqTSParagraph: this.reqTSParagraph, 280 reqFiscalImpact: this.reqFiscalImpact, 281 reqFNRequired: this.reqFNRequired, 282 reqEmergency: this.reqEmergency, 283 reqGovernor: this.reqGovernor, 284 reqBond: this.reqBond, 285 reqMandate: this.reqMandate, 286 reqPublicLand: this.reqPublicLand, 287 // end lawmaker/leap 288 showExtraParameters: this.showExtraParameters, 289 mustHave: this.mustHave, 290 mustNotHave: this.mustNotHave, 291 offset: this.searchOffset, 292 pageSize: this.pageSize, // page size for Elasticsearch defaults to 10, need to specifiy somewhere (code for server end set to default to 12) 293 sortByScore: this.sortByScore, 294 showBillText: this.showBillText, 295 sortAscending: this.sortAscending, 296 excludeOrders: this.excludeOrders, 297 separateSections: this.separateSections, // no point in passing this yet, but it would be good to figure out how to get ES to do the consolidation 298 } 299 }); 300 301 } 302 catch (err) { 303 this.err = {'message' : err.message}; 304 } 305 let results = []; 306 this.displayPageCount = 0; 307 if (response) { 308 this.numHits = response.data.hits.total.value; // numhits becomes obj with value and relation properties 309 results = response.data.hits.hits; 310 this.displayPageCount = this.pageSize; 311 } 312 313 return results; 314 }, 315 /** Get next page of search results */ 316 async nextResultsPage() { 317 if (this.numHits > this.pageSize) { 318 if (!this.err) { 319 this.searchOffset += this.pageSize; 320 } 321 this.displayOffset = this.searchOffset; 322 console.log(`searching NEXT ${this.searchOffset} of ${this.numHits}`); 323 this.searchResults = await this.search(); 324 document.documentElement.scrollTop = 0; 325 } 326 }, 327 /** Get previous page of search results */ 328 async prevResultsPage() { 329 if (!this.err) { 330 this.searchOffset -= this.pageSize; 331 if (this.searchOffset < 0) { 332 this.searchOffset = 0; 333 } 334 } 335 this.displayOffset = this.searchOffset; 336 console.log(`searching PREVIOUS ${this.searchOffset} of ${this.numHits}`); 337 this.searchResults = await this.search(); 338 document.documentElement.scrollTop = 0; 339 }, 340 showStatutePage(hit) { 341 window.open(hit._source.url, "_self"); 342 }, 343 async getMetadata(legislature) 344 { 345 let result = {} 346 result.committeeStatus = 1; 347 result.sponsorStatus = 1; 348 try { 349 const url = (legislature ? `${this.apiUrl}/QRY-CMTG-BY-LEG/${legislature}`: `${this.apiUrl}/QRY-CMTG-BY-LEG/`); 350 const committees = await axios.get(url); 351 this.committees = committees.data; 352 result.committeeStatus = committees.status; 353 //console.log(`committees: ${JSON.stringify(committees)}`) 354 355 const lmUrl = (legislature ? `${this.apiUrl}/QRY-SPNSR-LST/${legislature}`: `${this.apiUrl}/QRY-SPNSR-LST/`); 356 const sponsors = await axios.get(lmUrl); 357 //this.sponsors = sponsors.data; 358 this.sponsors = []; 359 sponsors.data.forEach(member => { 360 let memberRecord = this.sponsors.find(e => e.MemberCode == member.MemberCode); 361 if (memberRecord) { 362 memberRecord.legislatures.push(this.ordinal(member.SessionID + 116)); 363 } else { 364 member.legislatures = [this.ordinal(member.SessionID + 116) ]; 365 this.sponsors.push(member); 366 } 367 368 }) 369 result.sponsorStatus = sponsors.status; 370 //console.log(`members: ${JSON.stringify(this.sponsors)}`) 371 372 } catch (e) { 373 console.log(`ERROR, API retrieval, action metadata \n${e}`); 374 } finally { 375 console.log(`found committee list metadata, status ${result.committeeStatus}`) 376 console.log(`found ${this.sponsors.length} members, status ${result.sponsorStatus}`) 377 } 378 } 379 380 } 381});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.