17 from logilab.common.decorators import cached |
17 from logilab.common.decorators import cached |
18 |
18 |
19 from cubicweb import neg_role |
19 from cubicweb import neg_role |
20 from cubicweb.selectors import (match_kwargs, one_line_rset, non_final_entity, |
20 from cubicweb.selectors import (match_kwargs, one_line_rset, non_final_entity, |
21 specified_etype_implements, yes) |
21 specified_etype_implements, yes) |
22 from cubicweb.utils import make_uid |
|
23 from cubicweb.view import EntityView |
22 from cubicweb.view import EntityView |
24 from cubicweb.common import tags |
23 from cubicweb.common import tags |
25 from cubicweb.web import INTERNAL_FIELD_VALUE, RequestError, stdmsgs, eid_param |
24 from cubicweb.web import stdmsgs, eid_param |
26 from cubicweb.web import uicfg |
25 from cubicweb.web import uicfg |
27 from cubicweb.web.form import FormViewMixIn, FieldNotFound |
26 from cubicweb.web.form import FormViewMixIn, FieldNotFound |
28 from cubicweb.web.formfields import guess_field |
27 from cubicweb.web.formfields import guess_field |
29 from cubicweb.web.formwidgets import Button, SubmitButton, ResetButton |
28 from cubicweb.web.formwidgets import Button, SubmitButton, ResetButton |
30 from cubicweb.web.views import forms |
29 from cubicweb.web.views import forms |
135 return self.vreg['formrenderers'].select( |
134 return self.vreg['formrenderers'].select( |
136 'base', self.req, entity=entity, display_label=False, |
135 'base', self.req, entity=entity, display_label=False, |
137 display_help=False, display_fields=[(rtype, role)], table_class='', |
136 display_help=False, display_fields=[(rtype, role)], table_class='', |
138 button_bar_class='buttonbar', display_progress_div=False) |
137 button_bar_class='buttonbar', display_progress_div=False) |
139 |
138 |
140 def _build_form(self, entity, rtype, role, formid, default, reload, |
139 def _build_args(self, entity, rtype, role, formid, default, reload, lzone, |
|
140 extradata=None): |
|
141 divid = '%s-%s-%s' % (entity.eid, rtype, role) |
|
142 event_args = {'divid' : divid, 'eid' : entity.eid, 'rtype' : rtype, |
|
143 'reload' : dumps(reload), 'default' : default, 'role' : role, 'vid' : u'', |
|
144 'lzone' : lzone} |
|
145 if extradata: |
|
146 event_args.update(extradata) |
|
147 return divid, event_args |
|
148 |
|
149 def _build_form(self, entity, rtype, role, formid, default, reload, lzone, |
141 extradata=None, **formargs): |
150 extradata=None, **formargs): |
142 divid = '%s-%s-%s' % (entity.eid, rtype, role) |
151 divid, event_args = self._build_args(entity, rtype, role, formid, default, |
143 event_data = {'divid' : divid, 'eid' : entity.eid, 'rtype' : rtype, |
152 reload, lzone, extradata) |
144 'reload' : dumps(reload), 'default' : default, 'role' : role, 'vid' : u'', |
153 onsubmit = self._onsubmit % event_args |
145 'lzone' : self._build_landing_zone(None)} |
|
146 if extradata: |
|
147 event_data.update(extradata) |
|
148 onsubmit = self._onsubmit % event_data |
|
149 cancelclick = self._cancelclick % (entity.eid, rtype, divid) |
154 cancelclick = self._cancelclick % (entity.eid, rtype, divid) |
150 form = self.vreg['forms'].select( |
155 form = self.vreg['forms'].select( |
151 formid, self.req, entity=entity, domid='%s-form' % divid, |
156 formid, self.req, entity=entity, domid='%s-form' % divid, |
152 cssstyle='display: none', onsubmit=onsubmit, action='#', |
157 cssstyle='display: none', onsubmit=onsubmit, action='#', |
153 form_buttons=[SubmitButton(), Button(stdmsgs.BUTTON_CANCEL, |
158 form_buttons=[SubmitButton(), Button(stdmsgs.BUTTON_CANCEL, |
154 onclick=cancelclick)], |
159 onclick=cancelclick)], |
155 **formargs) |
160 **formargs) |
156 form.event_data = event_data |
161 form.event_args = event_args |
157 return form |
162 return form |
158 |
163 |
159 def cell_call(self, row, col, rtype=None, role='subject', |
164 def cell_call(self, row, col, rtype=None, role='subject', |
160 reload=False, # controls reloading the whole page after change |
165 reload=False, # controls reloading the whole page after change |
161 rvid=None, # vid to be applied to other side of rtype (non final relations only) |
166 rvid=None, # vid to be applied to other side of rtype (non final relations only) |
164 # (esp. needed when values are links) |
169 # (esp. needed when values are links) |
165 ): |
170 ): |
166 """display field to edit entity's `rtype` relation on click""" |
171 """display field to edit entity's `rtype` relation on click""" |
167 assert rtype |
172 assert rtype |
168 assert role in ('subject', 'object'), '%s is not an acceptable role value' % role |
173 assert role in ('subject', 'object'), '%s is not an acceptable role value' % role |
|
174 self.req.add_js('cubicweb.edition.js') |
|
175 self.req.add_css('cubicweb.form.css') |
169 if default is None: |
176 if default is None: |
170 default = xml_escape(self.req._('<no value>')) |
177 default = xml_escape(self.req._('<no value>')) |
171 entity = self.entity(row, col) |
178 entity = self.entity(row, col) |
172 rschema = entity.schema.rschema(rtype) |
179 rschema = entity.schema.rschema(rtype) |
173 lzone = self._build_landing_zone(landing_zone) |
180 lzone = self._build_landing_zone(landing_zone) |
174 # compute value, checking perms, build form |
181 # compute value, checking perms, build form |
175 if rschema.final: |
182 if rschema.final: |
176 form = self._build_form(entity, rtype, role, 'edition', default, reload, |
183 form = self._build_form(entity, rtype, role, 'edition', default, reload, lzone, |
177 attrcategories=self.attrcategories) |
184 attrcategories=self.attrcategories) |
178 if not self.should_edit_attribute(entity, rschema, role, form): |
185 if not self.should_edit_attribute(entity, rschema, role, form): |
179 self.w(entity.printable_value(rtype)) |
186 self.w(entity.printable_value(rtype)) |
180 return |
187 return |
181 value = entity.printable_value(rtype) or default |
188 value = entity.printable_value(rtype) or default |
191 value = default |
198 value = default |
192 if not self.should_edit_relation(entity, rschema, role, rvid): |
199 if not self.should_edit_relation(entity, rschema, role, rvid): |
193 if rset: |
200 if rset: |
194 self.w(value) |
201 self.w(value) |
195 return |
202 return |
196 form = self._build_form(entity, rtype, role, 'base', default, reload, |
203 form = self._build_form(entity, rtype, role, 'base', default, reload, lzone, |
197 dict(vid=rvid, lzone=lzone)) |
204 dict(vid=rvid, lzone=lzone)) |
198 field = guess_field(entity.e_schema, entity.schema.rschema(rtype), role) |
205 field = guess_field(entity.e_schema, entity.schema.rschema(rtype), role) |
199 form.append_field(field) |
206 form.append_field(field) |
200 self.relation_form(lzone, value, form, |
207 self.relation_form(lzone, value, form, |
201 self._build_renderer(entity, rtype, role)) |
208 self._build_renderer(entity, rtype, role)) |
203 def should_edit_attribute(self, entity, rschema, role, form): |
210 def should_edit_attribute(self, entity, rschema, role, form): |
204 rtype = str(rschema) |
211 rtype = str(rschema) |
205 ttype = rschema.targets(entity.id, role)[0] |
212 ttype = rschema.targets(entity.id, role)[0] |
206 afs = uicfg.autoform_section.etype_get(entity.id, rtype, role, ttype) |
213 afs = uicfg.autoform_section.etype_get(entity.id, rtype, role, ttype) |
207 if not (afs in self.attrcategories and entity.has_perm('update')): |
214 if not (afs in self.attrcategories and entity.has_perm('update')): |
208 self.w(entity.printable_value(rtype)) |
|
209 return False |
215 return False |
210 try: |
216 try: |
211 field = form.field_by_name(rtype, role) |
217 form.field_by_name(rtype, role) |
212 except FieldNotFound: |
218 except FieldNotFound: |
213 self.w(entity.printable_value(rtype)) |
|
214 return False |
219 return False |
215 return True |
220 return True |
216 |
221 |
217 def should_edit_relation(self, entity, rschema, role, rvid): |
222 def should_edit_relation(self, entity, rschema, role, rvid): |
218 if ((role == 'subject' and not rschema.has_perm(self.req, 'add', |
223 if ((role == 'subject' and not rschema.has_perm(self.req, 'add', |
230 | +-landing zone |
235 | +-landing zone |
231 +-value |
236 +-value |
232 +-form-xxx div |
237 +-form-xxx div |
233 """ |
238 """ |
234 w = self.w |
239 w = self.w |
235 w(u'<div id="%s-reledit" class="field">' % form.event_data['divid']) |
240 w(u'<div id="%s-reledit" class="field">' % form.event_args['divid']) |
236 w(tags.div(lzone, klass='editableField', id=form.event_data['divid'], |
241 w(tags.div(lzone, klass='editableField', id=form.event_args['divid'], |
237 onclick=self._onclick % form.event_data)) |
242 onclick=self._onclick % form.event_args)) |
238 w(value) |
243 w(value) |
239 w(form.form_render(renderer=renderer)) |
244 w(form.form_render(renderer=renderer)) |
240 w(u'</div>') |
245 w(u'</div>') |
241 |
246 |
242 |
247 |
|
248 class DummyForm(object): |
|
249 __slots__ = ('event_args',) |
|
250 def form_render(self, **_args): |
|
251 return u'' |
|
252 def append_field(self, *args): |
|
253 pass |
|
254 |
243 class AutoClickAndEditFormView(ClickAndEditFormView): |
255 class AutoClickAndEditFormView(ClickAndEditFormView): |
244 """same as ClickAndEditFormView but checking if the view *should* be applied |
256 """same as ClickAndEditFormView but checking if the view *should* be applied |
245 by checking uicfg configuration and composite relation property. |
257 by checking uicfg configuration and composite relation property. |
246 """ |
258 """ |
247 id = 'reledit' |
259 id = 'reledit' |
|
260 _onclick = (u"loadInlineEditionForm(%(eid)s, '%(rtype)s', '%(role)s', '%(eid)s', " |
|
261 "'%(divid)s', %(reload)s, '%(vid)s', '%(default)s', '%(lzone)s');") |
|
262 |
|
263 def should_edit_attribute(self, entity, rschema, role, _form): |
|
264 rtype = str(rschema) |
|
265 ttype = rschema.targets(entity.id, role)[0] |
|
266 afs = uicfg.autoform_section.etype_get(entity.id, rtype, role, ttype) |
|
267 if not (afs in self.attrcategories and entity.has_perm('update')): |
|
268 return False |
|
269 return True |
248 |
270 |
249 def should_edit_relation(self, entity, rschema, role, rvid): |
271 def should_edit_relation(self, entity, rschema, role, rvid): |
250 eschema = entity.e_schema |
272 eschema = entity.e_schema |
251 rtype = str(rschema) |
273 rtype = str(rschema) |
252 # XXX check autoform_section. what if 'generic'? |
274 # XXX check autoform_section. what if 'generic'? |
259 self.wview(rvid, entity.related(rtype, role), 'null') |
281 self.wview(rvid, entity.related(rtype, role), 'null') |
260 return False |
282 return False |
261 return super(AutoClickAndEditFormView, self).should_edit_relation( |
283 return super(AutoClickAndEditFormView, self).should_edit_relation( |
262 entity, rschema, role, rvid) |
284 entity, rschema, role, rvid) |
263 |
285 |
|
286 def _build_form(self, entity, rtype, role, formid, default, reload, lzone, |
|
287 extradata=None, **formargs): |
|
288 _divid, event_args = self._build_args(entity, rtype, role, formid, default, |
|
289 reload, lzone, extradata) |
|
290 form = DummyForm() |
|
291 form.event_args = event_args |
|
292 return form |
|
293 |
|
294 def _build_renderer(self, entity, rtype, role): |
|
295 pass |
264 |
296 |
265 class EditionFormView(FormViewMixIn, EntityView): |
297 class EditionFormView(FormViewMixIn, EntityView): |
266 """display primary entity edition form""" |
298 """display primary entity edition form""" |
267 id = 'edition' |
299 id = 'edition' |
268 # add yes() so it takes precedence over deprecated views in baseforms, |
300 # add yes() so it takes precedence over deprecated views in baseforms, |