1 | define(["dojo", "dojox", "dojox/data/JsonRestStore"], function(dojo, dojox) { |
---|
2 | |
---|
3 | // Contains code donated by Travis Tilley under CLA |
---|
4 | return dojo.declare("dojox.data.RailsStore", dojox.data.JsonRestStore, { |
---|
5 | constructor: function(){ |
---|
6 | // summary: |
---|
7 | // RailsStore is a data store for interacting with RESTful Rails controllers |
---|
8 | }, |
---|
9 | preamble: function(options){ |
---|
10 | if(typeof options.target == 'string' && !options.service){ |
---|
11 | var target = options.target.replace(/\/$/g, ''); |
---|
12 | |
---|
13 | // Special getRequest handler for handling content type negotiation via |
---|
14 | // the Rails format extension, as well as properly setting the ID param |
---|
15 | // in the URL. |
---|
16 | var getRequest = function(id, args){ |
---|
17 | args = args || {}; |
---|
18 | var url = target; |
---|
19 | var query; |
---|
20 | var ident; |
---|
21 | |
---|
22 | if(dojo.isObject(id)){ |
---|
23 | ident = ''; |
---|
24 | query = '?' + dojo.objectToQuery(id); |
---|
25 | }else if(args.queryStr && args.queryStr.indexOf('?') != -1){ |
---|
26 | ident = args.queryStr.replace(/\?.*/, ''); |
---|
27 | query = args.queryStr.replace(/[^?]*\?/g, '?'); |
---|
28 | }else if(dojo.isString(args.query) && args.query.indexOf('?') != -1){ |
---|
29 | ident = args.query.replace(/\?.*/, ''); |
---|
30 | query = args.query.replace(/[^?]*\?/g, '?'); |
---|
31 | }else{ |
---|
32 | ident = id ? id.toString() : ''; |
---|
33 | query = ''; |
---|
34 | } |
---|
35 | |
---|
36 | if(ident.indexOf('=') != -1){ |
---|
37 | query = ident; |
---|
38 | ident = ''; |
---|
39 | } |
---|
40 | |
---|
41 | if(ident){ |
---|
42 | url = url + '/' + ident + '.json' + query; |
---|
43 | }else{ |
---|
44 | url = url + '.json' + query; |
---|
45 | } |
---|
46 | |
---|
47 | var isSync = dojox.rpc._sync; |
---|
48 | dojox.rpc._sync = false; |
---|
49 | |
---|
50 | return { |
---|
51 | url : url, |
---|
52 | handleAs : 'json', |
---|
53 | contentType : 'application/json', |
---|
54 | sync : isSync, |
---|
55 | headers : { |
---|
56 | Accept : 'application/json,application/javascript', |
---|
57 | Range : args && (args.start >= 0 || args.count >= 0) |
---|
58 | ? "items=" |
---|
59 | + (args.start || '0') |
---|
60 | + '-' |
---|
61 | + ((args.count && (args.count |
---|
62 | + (args.start || 0) - 1)) || '') |
---|
63 | : undefined |
---|
64 | } |
---|
65 | }; |
---|
66 | }; |
---|
67 | |
---|
68 | options.service = dojox.rpc.Rest(this.target, true, null, |
---|
69 | getRequest); |
---|
70 | } |
---|
71 | }, |
---|
72 | fetch: function(args){ |
---|
73 | args = args || {}; |
---|
74 | function addToQueryStr(obj){ |
---|
75 | function buildInitialQueryString(){ |
---|
76 | if(args.queryStr == null){ |
---|
77 | args.queryStr = ''; |
---|
78 | } |
---|
79 | if(dojo.isObject(args.query)){ |
---|
80 | args.queryStr = '?' + dojo.objectToQuery(args.query); |
---|
81 | }else if(dojo.isString(args.query)){ |
---|
82 | args.queryStr = args.query; |
---|
83 | } |
---|
84 | } |
---|
85 | function separator(){ |
---|
86 | if(args.queryStr.indexOf('?') == -1){ |
---|
87 | return '?'; |
---|
88 | }else{ |
---|
89 | return '&'; |
---|
90 | } |
---|
91 | } |
---|
92 | if(args.queryStr == null){ |
---|
93 | buildInitialQueryString(); |
---|
94 | } |
---|
95 | args.queryStr = args.queryStr + separator() + dojo.objectToQuery(obj); |
---|
96 | } |
---|
97 | if(args.start || args.count){ |
---|
98 | // in addition to the content range headers, also provide query parameters for use |
---|
99 | // with the will_paginate plugin if so desired. |
---|
100 | if((args.start || 0) % args.count){ |
---|
101 | throw new Error("The start parameter must be a multiple of the count parameter"); |
---|
102 | } |
---|
103 | addToQueryStr({ |
---|
104 | page: ((args.start || 0) / args.count) + 1, |
---|
105 | per_page: args.count |
---|
106 | }); |
---|
107 | } |
---|
108 | if(args.sort){ |
---|
109 | // make the sort into query parameters |
---|
110 | var queryObj = { |
---|
111 | sortBy : [], |
---|
112 | sortDir : [] |
---|
113 | }; |
---|
114 | |
---|
115 | dojo.forEach(args.sort, function(item){ |
---|
116 | queryObj.sortBy.push(item.attribute); |
---|
117 | queryObj.sortDir.push(!!item.descending ? 'DESC' : 'ASC'); |
---|
118 | }); |
---|
119 | |
---|
120 | addToQueryStr(queryObj); |
---|
121 | delete args.sort; |
---|
122 | } |
---|
123 | |
---|
124 | return this.inherited(arguments); |
---|
125 | }, |
---|
126 | _processResults: function(results, deferred){ |
---|
127 | var items; |
---|
128 | |
---|
129 | /* |
---|
130 | * depending on the ActiveRecord::Base.include_root_in_json setting, |
---|
131 | * you might get back an array of attribute objects, or an array of |
---|
132 | * objects with the attribute object nested under an attribute having |
---|
133 | * the same name as the (remote and unguessable) model class. |
---|
134 | * |
---|
135 | * 'Example' without root_in_json: [{'id':1, 'text':'first'}] |
---|
136 | * 'Example' with root_in_json: [{'example':{'id':1, 'text':'first'}}] |
---|
137 | */ |
---|
138 | if((typeof this.rootAttribute == 'undefined') && results[0]){ |
---|
139 | if(results[0][this.idAttribute]){ |
---|
140 | this.rootAttribute = false; |
---|
141 | console.debug('RailsStore: without root_in_json'); |
---|
142 | }else{ |
---|
143 | for(var attribute in results[0]){ |
---|
144 | if(results[0][attribute][this.idAttribute]){ |
---|
145 | this.rootAttribute = attribute; |
---|
146 | console.debug('RailsStore: with root_in_json, attribute: ' + attribute); |
---|
147 | } |
---|
148 | } |
---|
149 | } |
---|
150 | } |
---|
151 | |
---|
152 | if(this.rootAttribute){ |
---|
153 | items = dojo.map(results, function(item){ |
---|
154 | return item[this.rootAttribute]; |
---|
155 | }, this); |
---|
156 | }else{ |
---|
157 | items = results; |
---|
158 | } |
---|
159 | |
---|
160 | // index the results |
---|
161 | var count = results.length; |
---|
162 | // if we don't know the length, and it is partial result, we will guess that it is twice as big, that will work for most widgets |
---|
163 | return {totalCount:deferred.fullLength || (deferred.request.count == count ? (deferred.request.start || 0) + count * 2 : count), items: items}; |
---|
164 | } |
---|
165 | }); |
---|
166 | |
---|
167 | }); |
---|