Safari fixes
[ajatus.git] / js / jqcouch.js
blob9db38adc798286748119462959ce09d27b68f6b2
1 /**
2  * jqCouchDB - jQuery plugin for couchdb connections
3  * @requires jQuery > v1.0.3
4  * @requires couchDB >= v0.7.0a5575
5  *
6  * http://protoblogr.net
7  *
8  * Copyright (c) 2007 Jerry Jalava (protoblogr.net)
9  * Dual licensed under the MIT and GPL licenses:
10  * http://www.opensource.org/licenses/mit-license.php
11  * http://www.gnu.org/licenses/gpl.html
12  *
13  * Version: 2.0.2
14  *
15  * Example usages:
16  *
18 # Database
20 var dbc = $.jqCouch.connection('db');
21 dbc.exists('database_name');
22 ---
23 if ($.jqCouch.connection('db').create('database_name').ok) {
24     alert("database created");
27 # Doc
29 var dc = $.jqCouch.connection('doc');
30 var rev = dc.get('database/document1')._rev;
31 ---
32 var doc = {_id:"0",a:1,b:1};
33 if ($.jqCouch.connection('doc').save('database_name', doc)._id !== false) {
34     alert("Created document with rev: "+doc._rev+", a="+doc.a);
36 ---
37 //Get all documents from database. (With cache)
38 var dc = $.jqCouch.connection('doc');
39 dc.update_config('cache', true);
40 if (var total_documents = dc.all('database_name').total_rows) {
41     var all_documents = dc.all('database_name').rows;    
43 //Get all documents from database. (Without cache)
44 var dc = $.jqCouch.connection('doc');
45 var all = dc.all('database_name');
46 if (all.total_rows > 0) {
47     var all_documents = all.rows;    
50 # View
52 var vc = $.jqCouch.connection('view');
53 if (vc.exists('database_name', 'event') !== false) {
54     alert("View "event" exists");
56 ---
57 if ($.jqCouch.connection('view').exists('database_name', 'event/all') !== false) {
58     alert("View "event/all" exists");
61 More examples can be found from the testsuite
63  */
65  /**
66   * @private
67   * Generates new connection instance
68   * @param {String} type Connection type to initiate
69   * @param {Mixed}(String/Function) map_fun Global result mapping function (Optional)
70   * @param {Object} config Global configuration for connection (Optional)
71   * @returns Connection handler
72   * @type Function
73   */
74 function jqCouch_connection(type, map_fun, config) {
75     var default_config = {
76         cache: false
77     };
78     
79     this.id = jQuery.jqCouch._generate_id();
80     this.type = type;
81     this.map_fun = map_fun || null;
82     this.inited = false;
83     this.config = jQuery.extend({}, default_config, config);
84     
85     var handler = false;
86     
87     this.destroy = function() {
88         this.id = null;
89     };
91     if (typeof eval('jqCouch_'+this.type) == 'function') {
92         eval('var fn = eval(jqCouch_'+this.type+'); handler = fn.apply(fn, [this.map_fun, config, this]);');
93     }
94     
95     handler.last_error = typeof handler.last_error == 'undefined' ? {} : handler.last_error;
96     handler.update_config = function(key, value) {
97         this.config[key] = value;
98         return true;
99     };
100     handler.last_results = typeof handler.last_results == 'undefined' ? {} : handler.last_results;
101     handler.purge_cache = function() {
102         handler.last_results = {};
103         return true;
104     };
105     
106     return handler;
110  * @private
111  * Handles DB actions
112  * @param {Mixed}(String/Function) map_fun Global result mapping function (Optional)
113  * @param {Object} config Global configuration for connection (Optional)
114  * @param {Function} conn Connection constructor instance
115  * @see jqCouch_connection
116  * @returns Connection handler
117  * @type Function
118  */
119 function jqCouch_db(map_fun, config, conn) {
120     var default_config = {
121         path: ''
122     };    
123     this.config = jQuery.extend({}, default_config, config);
124     conn.inited = true;
125     this.instance = conn;
126     var _self = this;
128     //TODO: add chance to create if doesnt exist    
129     this.exists = function(path, mf) {
130         if (typeof path == 'undefined') {
131             var path = this.config.path;
132         }
134         if (this.info(path, mf).db_name) {
135             return true;
136         }
137         
138         return false;
139     };
140     
141     this.info = function(path, mf) {
142         if (typeof path == 'undefined') {
143             var path = this.config.path;
144         }
145         if (path.substr(path.length-1,1) != '/') {
146             path += '/';
147         }
148                 
149         var map_fn = mf || map_fun;
150         
151         var results = false;
153         var lr_key = encodeURIComponent(path).toString();
154         if (   typeof this.last_results[lr_key] != 'undefined'
155             && this.config.cache)
156         {
157             return this.last_results[lr_key];
158         }
160         jQuery.ajax({
161             url: _self.config.server_url + path,
162             type: "GET",
163             global: _self.config.ajax_setup.global,
164             cache: _self.config.ajax_setup.cache,
165             async: false,
166             dataType: "json",
167             contentType: 'application/json',
168             error: function(req) {
169                 results = jQuery.extend({
170                     db_name: false
171                 }, jqCouch_map_error(req));
172                 _self.last_error = results;
173                 return false;
174             },
175             success: function(data) {
176                 results = jqCouch_map_results(data, map_fn);
177                 return true;
178             }
179         });
181         if (this.config.cache) {
182             this.last_results[lr_key] = results;
183         }
185         return results;
186     };
187     
188     this.create = function(path, mf) {
189         if (typeof path == 'undefined') {
190             var path = this.config.path;
191         }
192         if (path.substr(path.length-1,1) != '/') {
193             path += '/';
194         }
195         
196         var map_fn = mf || map_fun;
197         
198         var results = {
199             ok: false
200         };
202         jQuery.ajax({
203             url: _self.config.server_url + path,
204             type: "PUT",
205             global: _self.config.ajax_setup.global,
206             cache: _self.config.ajax_setup.cache,
207             async: false,
208             dataType: "json",
209             contentType: 'application/json',
210             error: function(req) {
211                 results = jQuery.extend({
212                     ok: false
213                 }, jqCouch_map_error(req));
214                 _self.last_error = results;
215                 return false;
216             },
217             success: function(data) {
218                 results = jqCouch_map_results(data, map_fn);
219                 return true;
220             }
221         });
222         
223         return results;
224     };
225     
226     this.del = function(path, mf) {
227         if (typeof path == 'undefined') {
228             var path = this.config.path;
229         }
230         if (path.substr(path.length-1,1) != '/') {
231             path += '/';
232         }
233                 
234         var map_fn = mf || map_fun;
235         
236         var results = {
237             ok: false
238         };
240         jQuery.ajax({
241             url: _self.config.server_url + path,
242             type: "DELETE",
243             global: _self.config.ajax_setup.global,
244             cache: _self.config.ajax_setup.cache,
245             async: false,
246             dataType: "json",
247             contentType: 'application/json',
248             error: function(req) {
249                 results = jQuery.extend({
250                     ok: false
251                 }, jqCouch_map_error(req));
252                 _self.last_error = results;
253                 return false;
254             },
255             success: function(data) {
256                 results = jqCouch_map_results(data, map_fn);
257                 return true;
258             }
259         });
260         
261         return results;
262     };
263     
264     this.all = function(mf) {  
265         var results = {
266             length: 0
267         };
268         
269         var map_fn = mf || map_fun;
271         var lr_key = encodeURIComponent(_self.config.server_url + '_all_dbs').toString();
272         if (   typeof this.last_results[lr_key] != 'undefined'
273             && this.config.cache)
274         {
275             return this.last_results[lr_key];
276         }
278         jQuery.ajax({
279             url: _self.config.server_url + '_all_dbs',
280             type: "GET",
281             global: _self.config.ajax_setup.global,
282             cache: _self.config.ajax_setup.cache,
283             async: false,
284             dataType: "json",
285             contentType: 'application/json',
286             error: function(req) {
287                 results = jqCouch_map_error(req);
288                 _self.last_error = results;
289                 return false;
290             },
291             success: function(data) {
292                 results = jqCouch_map_results(data, map_fn);
293                 return true;
294             }
295         });
297         if (this.config.cache) {
298             this.last_results[lr_key] = results;
299         }
301         return results;
302     };
303     
304     this.restart = function(mf) {
305         var result = {
306             ok: false
307         };
308         
309         var map_fn = mf || map_fun;
310         
311         jQuery.ajax({
312             url: _self.config.server_url + '_restart',
313             type: "POST",
314             global: _self.config.ajax_setup.global,
315             async: false,
316             error: function(req) {
317                 results = jQuery.extend({
318                     ok: false
319                 }, jqCouch_map_error(req));
320                 _self.last_error = results;
321                 return false;
322             },
323             success: function(data) {
324                 results = jqCouch_map_results(data, map_fn);
325                 return true;
326             }
327         });
329         return results;
330     };
331     
332     return this;
336  * @private
337  * Handles Doc actions
338  * @param {Mixed}(String/Function) map_fun Global result mapping function (Optional)
339  * @param {Object} config Global configuration for connection (Optional)
340  * @param {Function} conn Connection constructor instance
341  * @see jqCouch_connection
342  * @returns Connection handler
343  * @type Function
344  */
345 function jqCouch_doc(map_fun, config, conn) {
346     var default_config = {
347         path: ''
348     };    
349     this.config = jQuery.extend({}, default_config, config);
350     conn.inited = true;
351     this.instance = conn;
352     var _self = this;
353     
354     this.get = function(path, args, mf) {
355         if (   typeof path == 'undefined'
356             || path == '')
357         {
358             var path = this.config.path;
359         }
360         
361         var map_fn = mf || map_fun;
362         
363         var results = {
364             _id: false
365         };
366         
367         path += jQuery.jqCouch._generate_query_str(args);
369         var lr_key = encodeURIComponent(path).toString();
370         if (   typeof this.last_results[lr_key] != 'undefined'
371             && this.config.cache)
372         {
373             return this.last_results[lr_key];
374         }
376         jQuery.ajax({
377             url: _self.config.server_url + path,
378             type: "GET",
379             global: _self.config.ajax_setup.global,
380             cache: _self.config.ajax_setup.cache,
381             async: false,
382             dataType: "json",
383             contentType: 'application/json',
384             error: function(req) {
385                 results = jQuery.extend({
386                     _id: false
387                 }, jqCouch_map_error(req));
388                 _self.last_error = results;
389                 return false;
390             },
391             success: function(data) {
392                 results = jqCouch_map_results(data, map_fn);
393                 return true;
394             }
395         });
397         if (this.config.cache) {
398             this.last_results[lr_key] = results;
399         }
401         return results;
402     };
403     
404     this.all = function(path, args, mf) {
405         if (   typeof path == 'undefined'
406             || path == '')
407         {
408             var path = this.config.path;
409         }
410         if (path.substr(path.length-1,1) != '/') {
411             path += '/';
412         }
413         path += '_all_docs';
414         path += jQuery.jqCouch._generate_query_str(args);
415                 
416         var map_fn = mf || map_fun;
417         
418         var results = {
419             total_rows: 0
420         };
422         var lr_key = encodeURIComponent(path).toString();
423         if (   typeof this.last_results[lr_key] != 'undefined'
424             && this.config.cache)
425         {
426             return this.last_results[lr_key];
427         }
428         
429         jQuery.ajax({
430             url: _self.config.server_url + path,
431             type: "GET",
432             global: _self.config.ajax_setup.global,
433             cache: _self.config.ajax_setup.cache,
434             async: false,
435             dataType: "json",
436             contentType: 'application/json',
437             error: function(req) {
438                 results = jQuery.extend({
439                     total_rows: 0
440                 }, jqCouch_map_error(req));
441                 _self.last_error = results;
442                 return false;
443             },
444             success: function(data) {
445                 results = jqCouch_map_results(data, map_fn);
446                 return true;
447             }
448         });
449         
450         if (this.config.cache) {
451             this.last_results[lr_key] = results;
452         }
453         
454         return results;
455     };
456     
457     this.bulk_save = function(path, data, args, mf) {
458         if (   typeof path == 'undefined'
459             || path == '')
460         {
461             var path = this.config.path;
462         }        
463         if (path.substr(path.length-1,1) != '/') {
464             path += '/';
465         }
466         path += '_bulk_docs';
467         path += jQuery.jqCouch._generate_query_str(args);
469         var map_fn = mf || map_fun;
470         
471         var results = {
472             ok: false,
473             results: null
474         };
475         
476         jQuery.ajax({
477             url: _self.config.server_url + path,
478             type: "POST",
479             global: _self.config.ajax_setup.global,
480             cache: _self.config.ajax_setup.cache,
481             async: false,
482             dataType: "json",
483             contentType: 'application/json',
484             data: jQuery.jqCouch.toJSON(data),
485             processData: false,
486             error: function(req) {
487                 results = jQuery.extend({
488                     ok: false
489                 }, jqCouch_map_error(req));
490                 _self.last_error = results;
491                 return false;
492             },
493             success: function(data) {
494                 results = jqCouch_map_results(data, map_fn);
495                 return true;
496             }
497         });
498         
499         return results;
500     };
501     
502     this.save = function(path, data, mf) {
503         if (   typeof path == 'undefined'
504             || path == '')
505         {
506             var path = this.config.path;
507         }
508         if (path.substr(path.length-1,1) != '/') {
509             path += '/';
510         }
511         
512         var map_fn = mf || map_fun;
513         var results = false;
514         
515         if (   typeof data._id == 'undefined'
516             || data._id == '')
517         {
518             results = this.post(path, data, mf);
519         } else {
520             results = this.put(path + data._id, data, map_fn);
521         }
523         if (   results
524             && results.rev)
525         {
526             data._id = results.id;
527             data._rev = results.rev;
528         }
529         
530         return results;
531     };
532     
533     this.post = function(path, data, mf) {
534         if (   typeof path == 'undefined'
535             || path == '')
536         {
537             var path = this.config.path;
538         }
539         
540         var map_fn = mf || map_fun;
541         
542         var results = {
543             _id: false
544         };
545         
546         jQuery.ajax({
547             url: _self.config.server_url + path,
548             type: "POST",
549             global: _self.config.ajax_setup.global,
550             cache: _self.config.ajax_setup.cache,
551             async: false,
552             dataType: "json",
553             contentType: 'application/json',
554             data: jQuery.jqCouch.toJSON(data),
555             processData: false,
556             error: function(req) {
557                 results = jQuery.extend({
558                     _id: false
559                 }, jqCouch_map_error(req));
560                 _self.last_error = results;
561                 return false;
562             },
563             success: function(data) {
564                 results = jqCouch_map_results(data, map_fn);
565                 return true;
566             }
567         });
568         
569         return results;
570     };
571     
572     this.put = function(path, data, mf) {
573         if (   typeof path == 'undefined'
574             || path == '')
575         {
576             var path = this.config.path;
577         }
578         
579         var map_fn = mf || map_fun;
580         
581         var results = {
582             _id: false
583         };
585         jQuery.ajax({
586             url: _self.config.server_url + path,
587             type: "PUT",
588             data: jQuery.jqCouch.toJSON(data),
589             processData: false,
590             global: _self.config.ajax_setup.global,
591             cache: _self.config.ajax_setup.cache,
592             async: false,
593             dataType: "json",
594             contentType: 'application/json',
595             error: function(req) {
596                 results = jQuery.extend({
597                     _id: false
598                 }, jqCouch_map_error(req));
599                 _self.last_error = results;
600                 return false;
601             },
602             success: function(data) {
603                 results = jqCouch_map_results(data, map_fn);
604                 return true;
605             }
606         });
607         
608         return results;
609     };
610     
611     this.del = function(path, doc_or_rev, mf) {
612         if (   typeof path == 'undefined'
613             || path == '')
614         {
615             var path = this.config.path;
616         }
617         if (   typeof doc_or_rev == 'object'
618             && typeof doc_or_rev._id != 'undefined'
619             && typeof doc_or_rev._rev != 'undefined')
620         {
621             if (path.substr(path.length-1,1) != '/') {
622                 path += '/';
623             }
624             path += doc_or_rev._id;
625             
626             if (   typeof doc_or_rev._rev != 'undefined'
627                 && doc_or_rev._rev != null)
628             {
629                 path += '?rev=' + doc_or_rev._rev;                
630             }
631         }
632         if (typeof doc_or_rev == 'string') {
633             path += '?rev=' + doc_or_rev;
634         }
635         
636         var map_fn = mf || map_fun;
637         
638         var results = {
639             ok: false
640         };
641         
642         jQuery.ajax({
643             url: _self.config.server_url + path,
644             type: "DELETE",
645             global: _self.config.ajax_setup.global,
646             cache: _self.config.ajax_setup.cache,
647             async: false,
648             dataType: "json",
649             contentType: 'application/json',
650             error: function(req) {
651                 results = jQuery.extend({
652                     ok: false
653                 }, jqCouch_map_error(req));
654                 _self.last_error = results;
655                 return false;
656             },
657             success: function(data) {
658                 results = jqCouch_map_results(data, map_fn);
659                 return true;
660             }
661         });
662         
663         if (   typeof doc_or_rev == 'object'
664             && results.ok)
665         {
666             doc_or_rev._rev = results.rev;
667             doc_or_rev._deleted = true;
668         }
669         
670         return results;
671     };
672     
673     return this;
677  * @private
678  * Handles View actions
679  * @param {Mixed}(String/Function) map_fun Global result mapping function (Optional)
680  * @param {Object} config Global configuration for connection (Optional)
681  * @param {Function} conn Connection constructor instance
682  * @see jqCouch_connection
683  * @returns Connection handler
684  * @type Function
685  */
686 function jqCouch_view(map_fun, config, conn) {
687     var default_config = {
688         path: '',
689         language: "text/javascript"
690     };
691     this.config = jQuery.extend({}, default_config, config);
692     conn.inited = true;
693     this.instance = conn;
694     var _self = this;
695     
696     this.exists = function(path, view, mf) {
697         if (typeof path == 'undefined') {
698             var path = this.config.path;
699         }
700         
701         if (typeof view == 'undefined') {
702             return false;
703         }
704         
705         if (this.info(path, view, mf).views) {
706             return true;
707         }
708         
709         return false;
710     };
711     
712     this.info = function(path, view, mf) {
713         var results = {
714             _id: false,
715             views: false
716         };
717         if (typeof view == 'undefined') {
718             return results;
719         }
720         
721         if (typeof path == 'undefined') {
722             var path = this.config.path;
723         }
724         if (path.substr(path.length-1,1) != '/') {
725             path += '/';
726         }
727         path += '_design/';
728         
729         var view_parts = false;
730         if (view.toString().match(/\//)) {
731             view_parts = view.split("/");
732             path += view_parts[0];
733         } else {
734             path += view;
735         }
736         
737         path += '?revs_info=true';
738         
739         var map_fn = mf || map_fun;
741         var lr_key = encodeURIComponent(path).toString();
742         if (   typeof this.last_results[lr_key] != 'undefined'
743             && this.config.cache)
744         {
745             return this.last_results[lr_key];
746         }
748         jQuery.ajax({
749             url: _self.config.server_url + path,
750             type: "GET",
751             global: _self.config.ajax_setup.global,
752             cache: _self.config.ajax_setup.cache,
753             async: false,
754             dataType: "json",
755             contentType: 'application/json',
756             error: function(req) {
757                 results = jQuery.extend({
758                     _id: false,
759                     views: false
760                 }, jqCouch_map_error(req));
761                 _self.last_error = results;
762                 return false;
763             },
764             success: function(data) {
765                 if (   view_parts
766                     && typeof data.views[view_parts[1]] == 'undefined')
767                 {                    
768                     return false;
769                 }
770                 results = jqCouch_map_results(data, map_fn);
771                 if (typeof results['views'] == 'undefined') {
772                     results['views'] = false;
773                 }
774                 return true;
775             }
776         });
778         if (this.config.cache) {
779             this.last_results[lr_key] = results;
780         }
782         return results;
783     };
784     
785     this.get = function(path, name, args, mf) {
786         var results = {
787             total_rows: false
788         };
789         
790         if (   typeof path == 'undefined'
791             || path == '')
792         {
793             var path = this.config.path;
794         }
795         if (path.substr(path.length-1,1) != '/') {
796             path += '/';
797         }
798         if (! path.toString().match(/_view\//)) {
799             path += '_view/';
800         }
802         if (typeof name == 'undefined') {
803             return results;
804         }
806         if (! name.toString().match(/\//)) {
807             return results;
808         }
809         path += name;
810         
811         var map_fn = mf || map_fun;
812         
813         path += jQuery.jqCouch._generate_query_str(args);
814         
815         var lr_key = encodeURIComponent(path).toString();
816         if (   typeof this.last_results[lr_key] != 'undefined'
817             && this.config.cache)
818         {
819             return this.last_results[lr_key];
820         }
821         
822         jQuery.ajax({
823             url: _self.config.server_url + path,
824             type: "GET",
825             global: _self.config.ajax_setup.global,
826             cache: _self.config.ajax_setup.cache,
827             async: false,
828             dataType: "json",
829             contentType: 'application/json',
830             error: function(req) {
831                 results = jQuery.extend({
832                     total_rows: false
833                 }, jqCouch_map_error(req));
834                 _self.last_error = results;
835                 return false;
836             },
837             success: function(data) {
838                 results = jqCouch_map_results(data, map_fn);
839                 return true;
840             }
841         });
842         
843         if (this.config.cache) {
844             this.last_results[lr_key] = results;
845         }
846         
847         return results;
848     };
849     
850     this.save = function(path, data, mf) {
851         var results = {
852             ok: false
853         };
854         if (typeof data != 'object') {
855             return results;
856         }
857         
858         if (   typeof path == 'undefined'
859             || path == '')
860         {
861             var path = this.config.path;
862         }
863         if (path.substr(path.length-1,1) != '/') {
864             path += '/';
865         }
866         
867         if (typeof data._id == 'undefined') {
868             return results;
869         }
870         
871         if (! data._id.toString().match(/_design/)) {
872             data._id = '_design/' + data._id;
873         }
874         
875         if (typeof data['language'] == 'undefined') {
876             data.language = this.config.language;
877         }
878         
879         for (var name in data.views) {
880             if (typeof(data.views[name]['toSource']) == 'function') {
881                 data.views[name] = data.views[name].toSource();
882             } else {
883                 data.views[name] = data.views[name].toString();
884             }
885         }
886         
887         results = this.put(path + data._id, data, mf);
889         if (   results
890             && results.rev)
891         {
892             data._id = results.id;
893             data._rev = results.rev;
894         }
895         
896         return results;
897     };
898     
899     this.put = function(path, data, mf) {
900         if (   typeof path == 'undefined'
901             || path == '')
902         {
903             var path = this.config.path;
904         }
905         
906         var map_fn = mf || map_fun;
907         
908         var results = {
909             _id: false
910         };
912         jQuery.ajax({
913             url: _self.config.server_url + path,
914             type: "PUT",
915             data: jQuery.jqCouch.toJSON(data),
916             processData: false,
917             global: _self.config.ajax_setup.global,
918             cache: _self.config.ajax_setup.cache,
919             async: false,
920             dataType: "json",
921             contentType: 'application/json',
922             error: function(req) {
923                 results = jQuery.extend({
924                     _id: false
925                 }, jqCouch_map_error(req));
926                 _self.last_error = results;
927                 return false;
928             },
929             success: function(data) {
930                 results = jqCouch_map_results(data, map_fn);
931                 return true;
932             }
933         });
934         
935         return results;
936     };
938     this.del = function(path, doc_or_rev, mf) {
939         if (   typeof path == 'undefined'
940             || path == '')
941         {
942             var path = this.config.path;
943         }
944         if (   typeof doc_or_rev == 'object'
945             && typeof doc_or_rev._id != 'undefined'
946             && typeof doc_or_rev._rev != 'undefined')
947         {
948             if (path.substr(path.length-1,1) != '/') {
949                 path += '/';
950             }
951             path += doc_or_rev._id;
952             path += '?rev=' + doc_or_rev._rev;
953         }
954         if (typeof doc_or_rev == 'string') {
955             path += '?rev=' + doc_or_rev;
956         }
957         
958         var map_fn = mf || map_fun;
959         
960         var results = {
961             ok: false
962         };
963         
964         jQuery.ajax({
965             url: _self.config.server_url + path,
966             type: "DELETE",
967             global: _self.config.ajax_setup.global,
968             cache: _self.config.ajax_setup.cache,
969             async: false,
970             dataType: "json",
971             contentType: 'application/json',
972             error: function(req) {
973                 results = jQuery.extend({
974                     ok: false
975                 }, jqCouch_map_error(req));
976                 _self.last_error = results;
977                 return false;
978             },
979             success: function(data) {
980                 results = jqCouch_map_results(data, map_fn);
981                 return true;
982             }
983         });
984         
985         if (   typeof doc_or_rev == 'object'
986             && results.ok)
987         {
988             doc_or_rev._rev = results.rev;
989             doc_or_rev._deleted = true;
990         }
991         
992         return results;
993     };
994     
995     this.temp = function(path, map, args, mf) {
996         if (   typeof path == 'undefined'
997             || path == '')
998         {
999             var path = this.config.path;
1000         }
1001         if (path.substr(path.length-1,1) != '/') {
1002             path += '/';
1003         }
1004         path += '_temp_view';            
1005         path += jQuery.jqCouch._generate_query_str(args);
1007         var lr_key = encodeURIComponent(path).toString();
1008         if (   typeof this.last_results[lr_key] != 'undefined'
1009             && this.config.cache)
1010         {
1011             return this.last_results[lr_key];
1012         }
1013         
1014         var map_fn = mf || map_fun;
1015         
1016         if (typeof map == 'string') {
1017             map = eval(map);
1018         }
1019         
1020         if (typeof map['toSource'] == 'function') {
1021             map = map.toSource();
1022         } else {
1023             map = map.toString();
1024         }
1026         var results = {
1027             total_rows: false
1028         };
1030         jQuery.ajax({
1031             url: _self.config.server_url + path,
1032             type: "POST",
1033             global: _self.config.ajax_setup.global,
1034             cache: _self.config.ajax_setup.cache,
1035             async: false,
1036             dataType: "json",
1037             data: map,
1038             contentType: 'application/javascript',
1039             processData: false,
1040             error: function(req) {
1041                 results = jQuery.extend({
1042                     total_rows: false
1043                 }, jqCouch_map_error(req));
1044                 _self.last_error = results;
1045                 return false;
1046             },
1047             success: function(data) {
1048                 results = jqCouch_map_results(data, map_fn);
1049                 return true;
1050             }
1051         });
1053         if (this.config.cache) {
1054             this.last_results[lr_key] = results;
1055         }
1057         return results;
1058     };
1060     return this;
1064  * @private
1065  * Default result wrapper
1066  * @param {Object} data Results from query
1067  * @param {Mixed}(String/Function) map result mapping function (Optional)
1068  * @see jqCouch_db, jqCouch_doc, jqCouch_view
1069  * @returns Finished results
1070  * @type Object
1071  */
1072 function jqCouch_map_results(data, map) {
1073     if (typeof map == 'undefined') {
1074         return data;
1075     }
1076     
1077     if (typeof map == 'function') {
1078         var res = map.apply(map, [data]);
1079         return jQuery.extend({}, res || {});
1080     }
1081     
1082     if (typeof map == 'string') {        
1083         var fn = eval('('+map+')');
1084         var res = fn.apply(fn, [data]);
1085         return jQuery.extend({}, res || {});
1086     }
1087     
1088     return (data || {}); 
1092  * @private
1093  * Default error wrapper
1094  * @param {Object} req XHR Request object
1095  * @see jqCouch_db, jqCouch_doc, jqCouch_view
1096  * @returns Rendered error
1097  * @type Object
1098  */
1099 function jqCouch_map_error(req) {
1100     var results = {
1101         status: req.status,
1102         response: eval("(" + req.responseText + ")"),
1103         request: req
1104     };
1105     return results;
1108 (function($){
1109     
1110     $.jqCouch = {
1111         _connection_types: [
1112             'db', 'doc', 'view'
1113         ],
1114         _default_config: {
1115             server_url: '/',
1116             database: null,
1117             cache: false,
1118             ajax_setup: {
1119                 global: false,
1120                 cache: true
1121             }
1122         },
1123         _connections: {},
1124         
1125         _generate_id: function() {
1126             var rk = Math.floor(Math.random()*4013);
1127             return (10016486 + (rk * 22423));
1128         },
1129         
1130         _generate_query_str: function(qa) {
1131             var qs = '';
1132             if (typeof qa != 'undefined') {
1133                 qs += '?';
1134                 $.each(qa, function(k,v){
1135                     if (typeof v != 'string') {
1136                         qs += k + '=' + $.jqCouch.toJSON(v) + '&';                        
1137                     } else {
1138                         qs += k + '=' + v + '&';                        
1139                     }
1140                 });
1141                 qs = qs.substr(0, qs.length-1);
1142             }
1144             return qs;
1145         },
1146         
1147         parseJSON: function(json_str) {
1148                 try {
1149                 return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
1150                         json_str.replace(/"(\\.|[^"\\])*"/g, ''))) &&
1151                     eval('(' + json_str + ')');
1152             } catch(e) {
1153                 return false;
1154             }
1155         },
1156         toJSON: function (item, item_type) {
1157             var m = {
1158                 '\b': '\\b',
1159                 '\t': '\\t',
1160                 '\n': '\\n',
1161                 '\f': '\\f',
1162                 '\r': '\\r',
1163                 '"' : '\\"',
1164                 '\\': '\\\\'
1165             },
1166             s = {
1167                 arr: function (x) {
1168                     var a = ['['], b, f, i, l = x.length, v;
1169                     for (i = 0; i < l; i += 1) {
1170                         v = x[i];
1171                         v = conv(v);
1172                         if (typeof v == 'string') {
1173                             if (b) {
1174                                 a[a.length] = ',';
1175                             }
1176                             a[a.length] = v;
1177                             b = true;
1178                         }
1179                     }
1180                     a[a.length] = ']';
1181                     return a.join('');
1182                 },
1183                 bool: function (x) {
1184                     return String(x);
1185                 },
1186                 nul: function (x) {
1187                     return "null";
1188                 },
1189                 num: function (x) {
1190                     return isFinite(x) ? String(x) : 'null';
1191                 },
1192                 obj: function (x) {
1193                     if (x) {
1194                         if (x instanceof Array) {
1195                             return s.arr(x);
1196                         }
1197                         var a = ['{'], b, f, i, v;
1198                         for (i in x) {
1199                             v = x[i];
1200                             v = conv(v);
1201                             if (typeof v == 'string') {
1202                                 if (b) {
1203                                     a[a.length] = ',';
1204                                 }
1205                                 a.push(s.str(i), ':', v);
1206                                 b = true;
1207                             }
1208                         }
1209                         a[a.length] = '}';
1210                         return a.join('');
1211                     }
1212                     return 'null';
1213                 },
1214                 str: function (x) {
1215                     if (/["\\\x00-\x1f]/.test(x)) {
1216                         x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {
1217                             var c = m[b];
1218                             if (c) {
1219                                 return c;
1220                             }
1221                             c = b.charCodeAt();
1222                             return '\\u00' +
1223                             Math.floor(c / 16).toString(16) +
1224                             (c % 16).toString(16);
1225                         });
1226                     }
1227                     return '"' + x + '"';
1228                 }
1229             };
1230             var conv = function (x) {
1231                 var itemtype = typeof x;
1232                 switch(itemtype) {
1233                     case "array":
1234                         return s.arr(x);
1235                     break;
1236                     case "object":
1237                         return s.obj(x);
1238                     break;
1239                     case "string":
1240                         return s.str(x);
1241                     break;
1242                     case "number":
1243                         return s.num(x);
1244                     break;
1245                     case "null":
1246                         return s.nul(x);
1247                     break;
1248                     case "boolean":
1249                         return s.bool(x);
1250                     break;
1251                 };
1252             };
1254             var itemtype = item_type || typeof item;
1255             switch(itemtype) {
1256                 case "array":
1257                     return s.arr(item);
1258                 break;
1259                 case "object":
1260                     return s.obj(item);
1261                 break;
1262                 case "string":
1263                     return s.str(item);
1264                 break;
1265                 case "number":
1266                     return s.num(item);
1267                 break;
1268                 case "null":
1269                     return s.nul(item);
1270                 break;
1271                 case "boolean":
1272                     return s.bool(item);
1273                 break;                          
1274                 default:
1275                     throw("Unknown type for $.jqCouch.toJSON");
1276                 break;
1277             };
1278         },
1280         /**
1281          * Defines globally used default settings for jqCouch
1282          * @param {Object} defaults Config dictionary
1283          * @see $.jqCouch._default_config
1284          */        
1285         set_defaults: function(defaults) {
1286             $.jqCouch._default_config = $.extend({}, $.jqCouch._default_config, defaults || {});
1287         },
1288         
1289         /**
1290          * @public
1291          * Initiates new connection and returns it.
1292          * Possible parameter combinations:
1293          * type OR type, map_fun OR type, config OR type, map_fun, config
1294          * @param {String} type Type of connection to initiate
1295          * @param {Mixed}(String/Function) map_fun Global result mapping function
1296          * @param {Object} config Global configuration for connection
1297          * @see jqCouch_connection
1298          * @returns Connection handler
1299          * @type Function
1300          */
1301         connection: function() {
1302             if (arguments.length <= 0) {
1303                 return false;
1304             }
1305             
1306             if (typeof $.jqCouch._connections != 'object') {
1307                 $.jqCouch._connections = {};
1308             }
1310             var type = 'doc';
1311             var map_fun = null;
1312             var user_config = {};
1314             if ($.inArray(arguments[0], $.jqCouch._connection_types) != -1) {
1315                 type = arguments[0];
1316             } else {
1317                 return false;
1318             }
1320             if (arguments.length > 1) {
1321                 if (typeof arguments[1] == 'object') {
1322                     user_config = arguments[1];
1323                 } else {
1324                     map_fun = arguments[1];
1325                 }
1326             }
1327             
1328             if (   arguments.length == 3
1329                 && typeof arguments[2] == 'object')
1330             {
1331                 user_config = arguments[2];
1332             }
1333             
1334             var config = $.extend({}, $.jqCouch._default_config, user_config);
1335             
1336             var connection = new jqCouch_connection(type, map_fun, config);
1337             if (! connection.instance.inited) {
1338                 return false;
1339             }
1340             
1341             $.jqCouch._connections[connection.id] = connection;
1342             
1343             return connection;
1344         },
1345         
1346         destroy_connection: function(id) {
1347             if (   typeof $.jqCouch._connections[id] != 'undefined'
1348                 || $.jqCouch._connections[id] != 'null')
1349             {
1350                 $.jqCouch._connections[id].destroy();
1351                 $.jqCouch._connections[id] = null;
1352             }
1353             $.jqCouch._connections = $.grep($.jqCouch._connections, function(n,i){
1354                 if (n != null) {
1355                     return true;
1356                 }
1357             });
1358         }
1359     };
1360     
1361 })(jQuery);