1 //require <xataface/Permissions.js> 2 3 /*------------------------------------------------------------------------------- 4 * Xataface Web Application Framework 5 * Copyright (C) 2005-2009 Web Lite Solutions Corp (shannah@sfu.ca) 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 *------------------------------------------------------------------------------- 21 */ 22 /** 23 * This jquery plugin allows you to convert any HTML element or field into 24 * a record browser. Clicking the browser button will open a modal dialog 25 * that allows the user to search and browse through a number of records 26 * in a table. 27 * 28 * Example usage: 29 * 30 * <a href="#" id="selector">Click me to find stuff</a> 31 * ... 32 * 33 * $('#selector').RecordBrowser({ 34 * table: 'people', 35 * filters: { 36 * group_id: 10 37 * }, 38 * callback: function(values){ 39 * // values is an object with the records that the user 40 * // selected 41 * for ( var id in values ){ 42 * // id is the id of the record 43 * // values[id] is the title of the record 44 * } 45 * } 46 * }); 47 * 48 * Alternatively you could use the RecordBrowserWidget function to convert a text field 49 * into a RecordBrowser: 50 * 51 * <input type="text" id="textfield"/> 52 * ... 53 * $('#textfield').RecordBrowserWidget({ 54 * table: 'people', 55 * filters: { 56 * group_id: 10 57 * }, 58 * callback: function(values){ 59 * // values is an object with the records that the user 60 * // selected 61 * for ( var id in values ){ 62 * // id is the id of the record 63 * // values[id] is the title of the record 64 * } 65 * } 66 * }); 67 * 68 */ 69 (function ($){ 70 71 if ( typeof(console) == 'undefined' ) console = {'log': function(){}}; 72 if ( typeof(console.log) == 'undefined' ) console.log = function(){}; 73 74 var xataface = XataJax.load('xataface'); 75 xataface.RecordBrowser = function(o){ 76 /** 77 * The name of the table to browse for records in. 78 * @var string 79 */ 80 this.table = null; 81 82 /** 83 * The name of the column to use as the value in the option list. 84 * Set this value to __id__ to use the record id. 85 * If this value is blank, then the primary key is used so long as 86 * the primary key only has a single column. If it is a compound 87 * primary key, then the record id is used by default. 88 * @var string 89 */ 90 this.value = null; 91 92 /** 93 * The name of the column to use as the title in the option list. 94 * Set this value to __title__ to use the record title ( or leave blank). 95 * 96 * @var string 97 */ 98 this.text = null; 99 100 /** 101 * Search filters to add to the query. 102 * @var object 103 */ 104 this.filters = {}; 105 106 /** 107 * Callback function to be called with the selected values. 108 * function(values){} 109 * @var function 110 */ 111 this.callback = null; 112 113 /** 114 * The document element that is used to display the dialog. 115 * @var HTMLDOMElement 116 */ 117 this.el = document.createElement('div'); 118 119 /** 120 * The base url to the RecordBrowser directory. 121 * @var string 122 */ 123 this.baseURL = DATAFACE_URL+'/js/RecordBrowser'; 124 125 for ( var i in o ){ 126 this[i] = o[i]; 127 } 128 129 /** 130 * A flag to indicate whether the record select list 131 * needs to be updated when updateRecords() is called. 132 * The list would need to be updated if the filter parameters change. 133 * @var boolean 134 */ 135 this.dirty = true; 136 //$('head').append('<link rel="stylesheet" type="text/css" href="'+DATAFACE_URL+'/css/smoothness/jquery-ui-1.7.2.custom.css"/>'); 137 138 139 140 141 } 142 143 xataface.RecordBrowser.prototype = { 144 display : function(){ 145 var rb = this; 146 $('body').append(this.el); 147 $(this.el).load(this.baseURL+'/templates/RecordBrowser.html', function(){ 148 var dialog = this; 149 var searchChangeHandler = function(){ 150 rb.filterRecords({ 151 '-search' : $(this).val() 152 }); 153 }; 154 $(this).find('.xf-RecordBrowser-search-field') 155 .keyup(searchChangeHandler) 156 .change(searchChangeHandler); 157 //.blur(searchChangeHandler); 158 //$(this).find('.xf-RecordBrowser-select').css('height', '90%'); 159 $(this).find('.xf-RecordBrowser-select-field') 160 .css('width', '100%') 161 .attr('size', 8); 162 163 $(this).find('.xf-RecordBrowser-addnew-button').RecordDialog({ 164 table: rb.table, 165 callback: function(){ 166 rb.dirty=true; 167 rb.updateRecords(); 168 } 169 }); 170 171 $(this).dialog({ 172 'title': 'Select Record', 173 'buttons' : { 174 'Select' : function(){ 175 var out = {}; 176 $(dialog).find('.xf-RecordBrowser-select-field :selected').each(function(i, selected){ 177 out[$(selected).attr('value')] = $(selected).text(); 178 }); 179 180 if ( rb.callback ) rb.callback(out); 181 $(this).dialog("close"); 182 183 }, 184 'Cancel' : function(){ 185 $(this).dialog("close"); 186 187 } 188 189 }, 190 'position': 'center', 191 'modal' : true, 192 'resize': function(event, ui){ 193 $(dialog).find('.xf-RecordBrowser-select-field').css('height', ($(dialog).height()-60)+'px'); 194 195 } 196 }); 197 198 rb.updateRecords(); 199 }); 200 }, 201 202 filterRecords : function(filter){ 203 204 for ( var i in filter ){ 205 if ( this.filters[i] != filter[i] ) this.dirty = true; 206 this.filters[i] = filter[i]; 207 } 208 this.updateRecords(); 209 }, 210 211 updateRecords : function(){ 212 213 if ( this.dirty ){ 214 var sel = $(this.el).find('.xf-RecordBrowser-select-field'); 215 var val = $(sel).val(); 216 //var el = $(this.el); 217 sel.load(this.getDataURL(), function(){ 218 sel.val(val); 219 }); 220 this.dirty = false; 221 } 222 }, 223 224 getDataURL : function(){ 225 var url = DATAFACE_SITE_HREF+'?-action=RecordBrowser_data&-table='+encodeURIComponent(this.table); 226 if ( this.value ) url += '&-value='+encodeURIComponent(this.value); 227 if ( this.text ) url += '&-text='+encodeURIComponent(this.text); 228 for ( var i in this.filters ){ 229 url += '&'+encodeURIComponent(i)+'='+encodeURIComponent(this.filters[i]); 230 } 231 return url; 232 } 233 234 }; 235 236 $.fn.RecordBrowser = function(options){ 237 238 return this.each(function(){ 239 var obj = $(this); 240 obj.click(function(){ 241 if ( typeof(options.click) == 'function' ){ 242 options.click(); 243 } 244 var rb = new xataface.RecordBrowser(options); 245 rb.display(); 246 }); 247 }); 248 }; 249 250 $.fn.RecordBrowserWidget = function(options){ 251 return this.each(function(){ 252 253 var obj = $(this); 254 var editable = options.editable || false; 255 256 if ( obj.hasClass("xf-RecordBrowserWidget") ){ 257 // This field is already a record browser with different 258 // settings. We need to change it. So we remove the old 259 // display field. 260 var oldDisplayField = obj.next(); 261 var oldButton = oldDisplayField.next(); 262 oldDisplayField.remove(); 263 oldButton.remove(); 264 265 obj.removeClass('xf-RecordBrowserWidget'); 266 } 267 268 269 var displayField = document.createElement('input'); 270 $(displayField).attr('type','text') 271 .addClass('xf-RecordBrowserWidget-displayField') 272 //.css('width', obj.width()+'px') 273 //.css('height', obj.height()+'px') 274 .css('cursor', 'pointer') 275 //.css('border', '1px solid black') 276 .attr('readonly', 1); 277 278 279 $(displayField).insertAfter(this); 280 281 obj.css('display','none') 282 .addClass('xf-RecordBrowserWidget'); 283 284 if ( !options.frozen ){ 285 obj.change(function(){ 286 var id; 287 if ( options.value && options.value != '__id__' ){ 288 id = encodeURIComponent(options.value)+'='+encodeURIComponent(obj.val()); 289 } else { 290 id = obj.val(); 291 } 292 var url = DATAFACE_SITE_HREF+'?-action=RecordBrowser_lookup_single&-table='+options.table+'&-id='+encodeURIComponent(id); 293 if ( options.text ) url += '&-text='+encodeURIComponent(options.text); 294 $.get(url, function(text){ 295 $(displayField).val(text); 296 }); 297 298 updatePermissions(); 299 300 301 302 }); 303 304 /** 305 * Internal function to load the permissions for the currently selected record and then update 306 * whether the record can be edited or not. 307 */ 308 function updatePermissions(){ 309 try { 310 // Now we check the edit permission to find out if we need to show or hide the edit link 311 // for the field. 312 var theq = { 313 314 '-table': options.table 315 316 }; 317 318 if ( options.value && options.value != '__id__' ){ 319 theq[options.value] = obj.val(); 320 } else { 321 theq['--id'] = obj.val(); 322 } 323 324 var perms = new xataface.Permissions({ 325 query: theq 326 }); 327 //alert('here'); 328 perms.ready(function(){ 329 //alert('there'); 330 if ( perms.checkPermission('edit') ){ 331 editable = true; 332 } else { 333 editable = false; 334 } 335 updateEditable(); 336 337 }); 338 } catch (e){ 339 console.log('Looks like xataface.Permissions is not loaded while handling RecordBrowser change event.'); 340 console.log(e); 341 } 342 343 } 344 345 346 347 var a = document.createElement('a'); 348 $(a).addClass('xf-RecordBrowser-button') 349 .css('cursor', 'pointer') 350 .html('<img src="'+DATAFACE_URL+'/images/search_icon.gif" border="0" /><span class="xf-RecordBrowser-button-label"> Lookup</span>'); 351 $(a).find('.xf-RecordBrowser-button-label') 352 .css('display', 'none'); 353 354 355 356 357 358 359 360 $(a).insertAfter(displayField); 361 362 363 364 365 // If we want to allow editing, we add an edit button after the field that opens a record dialog 366 // for editing. 367 var editButton = $('<a>') 368 .addClass('xf-RecordBrowser-edit-button') 369 .html('<img src="'+DATAFACE_URL+'/images/edit.gif" border="0" /><span class="xf-RecordBrowser-button-label">Edit</span>') 370 .css({cursor: 'hand'}) 371 ; 372 373 $(editButton).find('.xf-RecordBrowser-button-label') 374 .css('display', 'none'); 375 376 377 $(editButton).click(function(){ 378 379 if ( !editable ){ 380 alert('This record is not currently editable.'); 381 } 382 var id = obj.val(); 383 if ( !id ){ 384 alert('No record is currently selected.'); 385 return; 386 } 387 388 var keyColName = '__id__'; 389 if ( options.value ){ 390 keyColName = options.value; 391 } 392 var recordid = encodeURIComponent(options.table)+'?'+encodeURIComponent(keyColName)+'='+encodeURIComponent(id); 393 var dlg = new xataface.RecordDialog({ 394 recordid: recordid, 395 table: options.table 396 }); 397 dlg.display(); 398 }); 399 400 $(editButton).insertAfter(a); 401 $(editButton).hide(); 402 403 function updateEditable(){ 404 if ( editable ) $(editButton).show(); 405 else $(editButton).hide(); 406 } 407 408 var origCallback = function(){}; 409 410 if ( typeof(options.callback == 'function' ) ){ 411 origCallback = options.callback; 412 } 413 options.callback = function(vals){ 414 for ( var i in vals ){ 415 //$(displayField).val(vals[i]); 416 obj.val(i); 417 obj.trigger('change'); 418 } 419 origCallback(vals, obj); 420 }; 421 422 $(a).RecordBrowser(options); 423 $(displayField).RecordBrowser(options); 424 } else { 425 //alert(obj.val()); 426 } 427 428 if ( obj.val() ){ 429 var id; 430 if ( options.value && options.value != '__id__' ){ 431 id = encodeURIComponent(options.value)+'='+encodeURIComponent(obj.val()); 432 } else { 433 id = obj.val(); 434 } 435 var url = DATAFACE_SITE_HREF+'?-action=RecordBrowser_lookup_single&-table='+options.table+'&-id='+encodeURIComponent(id); 436 if ( options.text ) url += '&-text='+encodeURIComponent(options.text); 437 $.get(url, function(text){ 438 //alert(text); 439 $(displayField).val(text); 440 }); 441 updatePermissions(); 442 } 443 444 445 }); 446 }; 447 })(jQuery);