def get(self, request): data = { str(cl): [{ "key": py2js(c[0]).strip('"'), "text": py2js(c[1]).strip('"') } for c in cl.get_choices()] for cl in kernel.CHOICELISTS.values() } return json_response(data)
def js_render_formpanel(self): yield "Lino.%s.FormPanel = Ext.extend(Lino.FormPanel,{" % self.main.rh.report yield " constructor : function(ww,config) {" for ln in jsgen.declare_vars(self.main.main): yield ' '+ln yield " config.items = %s;" % self.main.main.as_ext() if self.main.listeners: yield " config.listeners = %s;" % py2js(self.main.listeners) yield " config.before_row_edit = %s;" % py2js(self.main.before_row_edit) yield " Lino.%s.FormPanel.superclass.constructor.call(this, ww,config);" % self.main.rh.report yield " }" yield "});" yield ""
def add_help_text(self, kw, help_text, title, datasource, fieldname): if settings.SITE.use_quicktips: if settings.SITE.show_internal_field_names: ttt = "(%s.%s) " % (datasource, fieldname) else: ttt = '' if help_text: ttt = format_lazy(u"{}{}", ttt, help_text) if ttt: # kw.update(qtip=self.field.help_text) # kw.update(toolTipText=self.field.help_text) # kw.update(tooltip=self.field.help_text) kw.update(listeners=dict( render=js_code("Lino.quicktip_renderer(%s,%s)" % (py2js(title), py2js(ttt)))))
def js_render_detail_action_FormPanel(self, rh, action): rpt = rh.actor # ~ logger.info('20121005 js_render_detail_action_FormPanel(%s,%s)',rpt,action.full_name(rpt)) yield "" # ~ yield "// js_render_detail_action_FormPanel %s" % action dtl = action.get_window_layout() if dtl is None: raise Exception("action %s without detail?" % action.full_name()) # yield "Lino.%sPanel = Ext.extend(Lino.%s,{" % ( # action.full_name(), dtl._formpanel_name) # Ext.define('Ext.window.Window', { # extend: 'Ext.panel.Panel', yield "Ext.define('Lino.%sPanel', { extend : 'Lino.%s'," % ( action.full_name(), dtl._formpanel_name) yield " empty_title: %s," % py2js(action.get_button_label()) if action.action.hide_navigator: yield " hide_navigator: true," if rh.actor.params_panel_hidden: yield " params_panel_hidden: true," if action.action.save_action_name is not None: yield " save_action_name: %s," % py2js( action.action.save_action_name) yield " ls_bbar_actions: %s," % py2js( self.toolbar(rpt.get_toolbar_actions(action.action))) yield " ls_url: %s," % py2js(rpt.actor_url()) if action.action != rpt.default_action.action: yield " action_name: %s," % py2js(action.action.action_name) if isinstance(action.action, ShowInsert): yield " default_record_id: -99999," yield " initComponent : function() {" a = rpt.detail_action if a: yield " this.ls_detail_handler = Lino.%s;" % a.full_name() a = rpt.insert_action if a: yield " this.ls_insert_handler = Lino.%s;" % a.full_name() # yield " Lino.%sPanel.superclass.initComponent.call(this);" \ # % action.full_name() # this.callParent(arguments); # this.callSuper(arguments); yield " this.callSuper();" yield " }" yield "});" yield ""
def ar2js(self, ar, obj, **status): """Implements :meth:`lino.core.renderer.HtmlRenderer.ar2js`. """ rp = ar.requesting_panel ba = ar.bound_action params = {} if ba.action.is_window_action(): # is_window_action is known in the json file, just run action as normal # Unsure what data is added with this, but likely want to include it. # print("1.19.2019", status) status.update(self.get_action_status(ar, ba, obj)) params.update(status) params.update(self.get_action_params(ar, ba, obj)) params.update(status) js_obj = { "rp": rp, "an": ba.action.action_name, "onMain": ar.is_on_main_actor, "actorId": ba.actor.actor_id, "status": params } if hasattr(obj, "pk"): js_obj["sr"] = obj.pk # else "-99998", # -99998 might be wrong for many commands... need to know what logic is used to determn it, elif isinstance(obj, list): js_obj["sr"] = obj return "window.App.runAction(%s)" % (py2js(js_obj))
def get(self, request, app_label=None, actor=None, pk=None, fldname=None, tplname=None, **kw): if request.method == 'GET': rpt = requested_actor(app_label, actor) elem = rpt.get_row_by_pk(None, pk) if elem is None: raise http.Http404("%s %s does not exist." % (rpt, pk)) TextFieldTemplate = rt.modules.tinymce.TextFieldTemplate if tplname: tft = TextFieldTemplate.objects.get(pk=int(tplname)) if settings.SITE.trusted_templates: #~ return http.HttpResponse(tft.text) template = JinjaTemplate(tft.text) context = dict(request=request, instance=elem, **rt.modules) return http.HttpResponse(template.render(**context)) else: return http.HttpResponse(tft.text) qs = TextFieldTemplate.objects.all().order_by('name') templates = [] for obj in qs: url = dd.plugins.tinymce.build_plain_url( 'templates', app_label, actor, pk, fldname, str(obj.pk)) templates.append([ str(obj.name), url, str(obj.description)]) js = "var tinyMCETemplateList = %s;" % py2js(templates) return http.HttpResponse(js, content_type='text/json') raise http.Http404("Method %r not supported" % request.method)
def get_head_lines(self, site, request): from lino.utils.jsgen import py2js if not self.site.use_websockets: return user_name = "anony" if request.user.authenticated: user_name = request.user.username site_title = site.title js_to_add = """ <script type="text/javascript"> Ext.onReady(function() { // Note that the path doesn't matter for routing; any WebSocket // connection gets bumped over to WebSocket consumers var ws_scheme = window.location.protocol == "https:" ? "wss" : "ws"; var ws_path = ws_scheme + '://' + window.location.host + ":8443/websocket/"; console.log("Connecting to " + ws_path); var socket = new ReconnectingWebSocket(ws_path); onGranted = console.log("onGranted"); onDenied = console.log("onDenied"); // Ask for permission if it's not already granted Push.Permission.request(onGranted,onDenied); socket.onmessage = function(e) { try { var json_data = JSON.parse(e.data); Push.create( %s , { body: json_data['body'], icon: '/static/img/lino-logo.png', onClick: function () { window.focus(); Lino.viewport.refresh(); this.close(); } }); if (false && Number.isInteger(JSON.parse(e.data)["id"])){ socket.send(JSON.stringify({ "command": "seen", "message_id": JSON.parse(e.data)["id"], })); } } catch(err) { console.log(err.message); } } // Call onopen directly if socket is already open if (socket.readyState == WebSocket.OPEN) socket.onopen(); else { socket.onopen = function() { socket.send(JSON.stringify({ "command": "user_connect", "username": "******", })); } } }); // end of onReady()" </script> """ % (py2js(site_title), user_name) yield js_to_add
def get_head_lines(self, site, request): from lino.utils.jsgen import py2js if not self.site.use_websockets: return user_name = "anony" if request.user.authenticated: user_name = request.user.username site_title = site.title or 'Lino-framework' js_to_add = """ <script type="text/javascript"> Ext.onReady(function() { // Note that the path doesn't matter for routing; any WebSocket // connection gets bumped over to WebSocket consumers var ws_scheme = window.location.protocol == "https:" ? "wss" : "ws"; var ws_path = ws_scheme + '://' + window.location.host + "/lino"; console.log("Connecting to " + ws_path); var socket = new RobustWebSocket(ws_path); onGranted = console.log("onGranted"); onDenied = console.log("onDenied"); // Ask for permission if it's not already granted Push.Permission.request(onGranted,onDenied); socket.onmessage = function(e) { try { var json_data = JSON.parse(e.data); Push.create( %s , { body: json_data['body'], icon: '/static/img/lino-logo.png', onClick: function () { window.focus(); Lino.viewport.refresh(); this.close(); } }); if (false && Number.isInteger(JSON.parse(e.data)["id"])){ socket.send(JSON.stringify({ "command": "seen", "message_id": JSON.parse(e.data)["id"], })); } } catch(err) { console.log(err.message); } } // Call onopen directly if socket is already open if (socket.readyState == WebSocket.OPEN) socket.onopen(); else { socket.onopen = function() { socket.send(JSON.stringify({ "command": "user_connect", "username": "******", })); } } }); // end of onReady()" </script> """ % (py2js(site_title), user_name) yield js_to_add
def get(self,request, app_label=None,actor=None,pk=None,fldname=None,tplname=None,**kw): if request.method == 'GET': from lino.models import TextFieldTemplate if tplname: tft = TextFieldTemplate.objects.get(pk=int(tplname)) return http.HttpResponse(tft.text) rpt = requested_actor(app_label,actor) elem = rpt.get_row_by_pk(pk) if elem is None: raise http.Http404("%s %s does not exist." % (rpt,pk)) #~ TextFieldTemplate.templates m = getattr(elem,"%s_templates" % fldname,None) if m is None: q = models.Q(user=request.user) | models.Q(user=None) #~ q = models.Q(user=request.user) qs = TextFieldTemplate.objects.filter(q).order_by('name') else: qs = m(request) templates = [] for obj in qs: url = settings.LINO.build_admin_url('templates', app_label,actor,pk,fldname,unicode(obj.pk)) templates.append([ unicode(obj.name),url,unicode(obj.description)]) js = "var tinyMCETemplateList = %s;" % py2js(templates) return http.HttpResponse(js,content_type='text/json') raise http.Http404("Method %r not supported" % request.method)
def js_render(self): yield "Lino.%s = function(caller,params) { " % self.action #~ yield "function(caller,params) { " #~ yield " Ext.getCmp('main_area').el.setStyle({cursor:'wait'});" #~ yield "Lino.notify();" if False and settings.USE_FIREBUG: yield " console.time('%s');" % self.action #~ yield " console.log('ext_windows',20100930,params);" yield " var ww = new Lino.%s(caller,%s);" % ( self.__class__.__name__,py2js(self.config)) """HACK : override default jsgen behaviour. The main component has no options, but must take those passed to this function as `params`. """ if self.main.value: raise Exception("Oops, value is %r" % self.main.value) v = self.main yield " params.containing_window = ww;" yield " var %s = %s;" % (v.ext_name,(v.value_template % 'params')) #~ self.main.value = 'params' ## ugly HACK! #~ for ln in jsgen.declare_vars(self.main): #~ yield ' ' + ln yield " ww.main_item = %s;" % self.main.as_ext() yield " ww.show();" if False and settings.USE_FIREBUG: yield " console.timeEnd('%s');" % self.action yield "};"
def get(self, request, app_label=None, actor=None, pk=None, fldname=None, tplname=None, **kw): if request.method == 'GET': rpt = requested_actor(app_label, actor) elem = rpt.get_row_by_pk(None, pk) if elem is None: raise http.Http404("%s %s does not exist." % (rpt, pk)) TextFieldTemplate = rt.modules.tinymce.TextFieldTemplate if tplname: tft = TextFieldTemplate.objects.get(pk=int(tplname)) if settings.SITE.trusted_templates: #~ return http.HttpResponse(tft.text) template = JinjaTemplate(tft.text) context = dict(request=request, instance=elem, **rt.modules) return http.HttpResponse(template.render(**context)) else: return http.HttpResponse(tft.text) qs = TextFieldTemplate.objects.all().order_by('name') templates = [] for obj in qs: url = dd.plugins.tinymce.build_plain_url( 'templates', app_label, actor, pk, fldname, unicode(obj.pk)) templates.append([ unicode(obj.name), url, unicode(obj.description)]) js = "var tinyMCETemplateList = %s;" % py2js(templates) return http.HttpResponse(js, content_type='text/json') raise http.Http404("Method %r not supported" % request.method)
def as_js(self, name): """ possible side effect. but self.options is used only for as_js(), and in case of virtual remote fields they use the virtual field's delegate as_js method but with their own name. """ self.options.update(name=name) return py2js(self.options)
def add_help_text(self, kw, help_text, title, datasource, fieldname): if settings.SITE.use_quicktips: if settings.SITE.show_internal_field_names: ttt = "(%s.%s) " % (datasource, fieldname) else: ttt = '' if help_text: ttt = format_lazy(u"{}{}", ttt, help_text) if ttt: # kw.update(qtip=self.field.help_text) # kw.update(toolTipText=self.field.help_text) # kw.update(tooltip=self.field.help_text) kw.update(listeners=dict(render=js_code( "Lino.quicktip_renderer(%s,%s)" % ( py2js(title), py2js(ttt))) ))
def js_render_ParamsPanelSubclass(self, dh): yield "" yield "Lino.%s = Ext.extend(Ext.form.FormPanel, {" % \ dh.layout._formpanel_name for k, v in list(dh.main.ext_options().items()): # ~ if k != 'items': if not k in self.SUPPRESSED: yield " %s: %s," % (k, py2js(v)) # ~ yield " collapsible: true," # if dh.main.value.get('layout', False): if (type(dh.main.value['layout']) is str and dh.main.value['layout'] == 'hbox') or ( type(dh.main.value['layout']) is dict and dh.main.value['layout'].get('type', False) == 'hbox'): # if dh.main.value['layout'] == 'hbox': yield " layout: 'hbox'," else: yield " layout: 'form'," yield " autoHeight: true," # ~ if dh.layout.window_size and dh.layout.window_size[1] == 'auto': # ~ yield " autoHeight: true," yield " initComponent : function() {" # 20140503 yield " var containing_panel = this;" lc = 0 for ln in jsgen.declare_vars(dh.main.elements): yield " " + ln lc += 1 if lc == 0: # print 20150626, dh.main.elements[0].required_roles # print 20150626, jsgen._for_user_profile.__class__ msg = "%r of %s has no variables" % (dh.main, dh) msg += ", datasource: %r, other datasources: %r" % ( dh.layout._datasource, dh.layout._other_datasources) msg += ", main elements: %r" % dh.main.elements # raise Exception(msg) print((20150717, msg)) yield " this.items = %s;" % py2js(dh.main.elements) yield " this.fields = %s;" % py2js([ e for e in dh.main.walk() if isinstance(e, ext_elems.FieldElement) ]) # yield " Lino.%s.superclass.initComponent.call(this);" % \ # dh.layout._formpanel_name yield "this.callSuper();" yield " }" yield "});" yield ""
def __init__(self,lh,name,dv,**kw): #~ self.dv = dv kw.update(store=js_code('this.store')) kw.update(tpl=js_code('new Ext.XTemplate(%s)' % py2js(dv.xtemplate))) kw.update(emptyText='No images to display') kw.update(itemSelector='div.thumb-wrap') kw.update(loadingText='Loading...') LayoutElement.__init__(self,lh,name,**kw)
def as_js(self, name): """ Return a Javascript string which defines this atomizer as an object. This is used by :mod:`lino.modlib.extjs.ext_renderer`. and in case of virtual remote fields they use the virtual field's delegate as_js method but with their own name. """ self.options.update(name=name) return py2js(self.options)
def json_response(x, content_type='application/json', status=200): if True: s = py2js(x) else: try: s = py2js(x) except Exception as e: raise Exception("Failed to render {!r} : {}".format(x, e)) # Theroretically we should send content_type='application/json' # (http://stackoverflow.com/questions/477816/the-right-json-content-type), # but "File uploads are not performed using Ajax submission, that # is they are not performed using XMLHttpRequests. (...) If the # server is using JSON to send the return object, then the # Content-Type header must be set to "text/html" in order to tell # the browser to insert the text unchanged into the document # body." # (http://docs.sencha.com/ext-js/3-4/#!/api/Ext.form.BasicForm) # See 20120209. return http.HttpResponse(s, content_type=content_type, status=status)
def action_call(self, request, bound_action, status): a = bound_action.action if a.opens_a_window or (a.parameters and not a.no_params_window): fullname = ".".join(bound_action.full_name().rsplit( ".", 1)[::-1]) # moves action name to first arg, if request and request.subst_user: status[constants.URL_PARAM_SUBST_USER] = request.subst_user if isinstance(a, ShowEmptyTable): status.update(record_id=-99998) if request is None: rp = None else: rp = request.requesting_panel if not status: status = { } # non param window actions also use router and just have no args, return "Lino.window_action(%s,%s,%s)" % (py2js(fullname), py2js(status), py2js(rp)) # todo: have action buttons forward their requests to the server with this js link return "%s()" % self.get_panel_btn_handler(bound_action)
def ar2js(self, ar, obj, **status): """Implements :meth:`lino.core.renderer.HtmlRenderer.ar2js`. """ rp = ar.requesting_panel ba = ar.bound_action if ba.action.is_window_action(): # Window actions have been generated by # js_render_window_action(), so we just call its `run(`) # method: status.update(self.get_action_status(ar, ba, obj)) return "Lino.%s.run(%s,%s)" % ( ba.full_name(), py2js(rp), py2js(status)) # It's a custom ajax action generated by # js_render_custom_action(). # 20140429 `ar` is now None, see :ref:`welfare.tested.integ` params = self.get_action_params(ar, ba, obj) return "Lino.%s(%s,%s,%s)" % ( ba.full_name(), py2js(rp), py2js(obj.pk), py2js(params))
def json_response(x, content_type='application/json'): s = py2js(x) """ Theroretically we should send content_type='application/json' (http://stackoverflow.com/questions/477816/the-right-json-content-type), but "File uploads are not performed using Ajax submission, that is they are not performed using XMLHttpRequests. (...) If the server is using JSON to send the return object, then the Content-Type header must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body." (http://docs.sencha.com/ext-js/3-4/#!/api/Ext.form.BasicForm) See 20120209. """ return http.HttpResponse(s, content_type=content_type)
def json_response(x,content_type='application/json'): s = py2js(x) """ Theroretically we should send content_type='application/json' (http://stackoverflow.com/questions/477816/the-right-json-content-type), but "File uploads are not performed using Ajax submission, that is they are not performed using XMLHttpRequests. (...) If the server is using JSON to send the return object, then the Content-Type header must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body." (http://docs.sencha.com/ext-js/3-4/#!/api/Ext.form.BasicForm) See 20120209. """ return http.HttpResponse(s, content_type=content_type)
def ar2js(self, ar, obj, **status): """Implements :meth:`lino.core.renderer.HtmlRenderer.ar2js`. """ rp = ar.requesting_panel ba = ar.bound_action if ba.action.is_window_action(): # Window actions have been generated by # js_render_window_action(), so we just call its `run(`) # method: status.update(self.get_action_status(ar, ba, obj)) return "Lino.%s.run(%s,%s)" % ( ba.full_name(), py2js(rp), py2js(status)) # It's a custom ajax action generated by # js_render_custom_action(). # 20140429 `ar` is now None, see :ref:`welfare.tested.integ` if ba.action.select_rows: params = self.get_action_params(ar, ba, obj) return "Lino.%s(%s,%s,%s,%s)" % ( ba.full_name(), py2js(rp), py2js(ar.is_on_main_actor), py2js(obj.pk), py2js(params)) # assert obj is None # return "oops" # params = self.get_action_params(ar, ba, obj) # url = ar.get_request_url() url = self.plugin.build_plain_url( ar.actor.app_label, ar.actor.__name__) params = ar.get_status().get('base_params', None) pp = "function() {return %s;}" % py2js(params) return "Lino.list_action_handler(%s,%s,%s,%s)()" % ( py2js(url), py2js(ba.action.action_name), py2js(ba.action.http_method),pp)
def action_call(self, request, bound_action, status): a = bound_action.action # fullname = ".".join(bound_action.full_name().rsplit(".", 1)[::-1]) # moves action name to first arg, actorId, an = bound_action.full_name().rsplit(".", 1) if request and request.subst_user: status[constants.URL_PARAM_SUBST_USER] = request.subst_user if isinstance(a, ShowEmptyTable): status.update(record_id=-99998) rp = None if request is None else request.requesting_panel if not status: status = {} return "window.App.runAction(%s)" % py2js( dict(an=an, actorId=actorId, status=status, rp=rp))
def ar2js(self, ar, obj, **status): """Implements :meth:`lino.core.renderer.HtmlRenderer.ar2js`. """ rp = ar.requesting_panel ba = ar.bound_action if ba.action.is_window_action(): # Window actions have been generated by # js_render_window_action(), so we just call its `run(`) # method: status.update(self.get_action_status(ar, ba, obj)) return "Lino.%s.run(%s,%s)" % (ba.full_name(), py2js(rp), py2js(status)) # It's a custom ajax action generated by # js_render_custom_action(). # 20140429 `ar` is now None, see :ref:`welfare.tested.integ` if ba.action.select_rows: params = self.get_action_params(ar, ba, obj, **status) pk = obj.pk if isinstance(obj, models.Model) else obj return ( f"Lino.{ba.full_name()}({py2js(rp)},{py2js(ar.is_on_main_actor)},{py2js(pk)},{py2js(params)})" ) # assert obj is None # params = self.get_action_params(ar, ba, obj) # url = ar.get_request_url() url = self.front_end.build_plain_url(ar.actor.app_label, ar.actor.__name__) params = ar.get_status().get( 'base_params', None ) # dont use **statuc on ar.get_status to not modify existing code. rqData, xcallback = py2js(status.get("rqdata", None)), py2js( status.get("xcallback", None)) pp = "function() {return %s;}" % py2js(params) return "Lino.list_action_handler(%s,%s,%s,%s,%s,%s)()" % ( py2js(url), py2js(ba.action.action_name), py2js(ba.action.http_method), pp, rqData, xcallback)
def get(self,request, app_label=None,actor=None,pk=None,fldname=None,tplname=None,**kw): if request.method == 'GET': rpt = requested_actor(app_label,actor) elem = rpt.get_row_by_pk(None,pk) if elem is None: raise http.Http404("%s %s does not exist." % (rpt,pk)) if tplname: tft = TextFieldTemplate.objects.get(pk=int(tplname)) if settings.SITE.trusted_templates: #~ return http.HttpResponse(tft.text) template = JinjaTemplate(tft.text) context = dict(request=request,instance=elem,**settings.SITE.modules) return http.HttpResponse(template.render(**context)) else: return http.HttpResponse(tft.text) #~ q = models.Q(user=request.user) | models.Q(user__group__in=request.user.group_set.all()) teams = [o.group for o in request.user.users_membership_set_by_user.all()] flt = models.Q(team__isnull=True) | models.Q(team__in=teams) qs = TextFieldTemplate.objects.filter(flt).order_by('name') #~ m = getattr(elem,"%s_templates" % fldname,None) #~ if m is None: #~ q = models.Q(user=request.user) | models.Q(user=None) #~ qs = TextFieldTemplate.objects.filter(q).order_by('name') #~ else: #~ qs = m(request) templates = [] for obj in qs: url = settings.SITE.build_admin_url('templates', app_label,actor,pk,fldname,unicode(obj.pk)) templates.append([ unicode(obj.name),url,unicode(obj.description)]) js = "var tinyMCETemplateList = %s;" % py2js(templates) return http.HttpResponse(js,content_type='text/json') raise http.Http404("Method %r not supported" % request.method)
def js_render(self): yield "Lino.%s = function(caller,params) { " % self.action #~ yield "function(caller,params) { " #~ yield " Ext.getCmp('main_area').el.setStyle({cursor:'wait'});" #~ yield "Lino.notify();" if False and settings.USE_FIREBUG: yield " console.time('%s');" % self.action #~ yield " console.log('ext_windows',20100930,params);" for ln in jsgen.declare_vars(self.main): yield ' '+ln #~ yield " ww.main_item = %s;" % yield " var ww = new Lino.%s(caller,%s,%s,params);" % ( self.main.as_ext(), self.__class__.__name__,py2js(self.config)) yield " ww.show();" if False and settings.USE_FIREBUG: yield " console.timeEnd('%s');" % self.action yield "}"
def write_lino_js(self, f): """ :param f: File object :return: 1 """ choicelists_data = { # ID: [{"value": py2js(c[0]).strip('"'), "text": py2js(c[1]).strip('"')} for c in cl.get_choices()] for ID: [{ "value": c[0].value, "text": str(c[1]) } for c in cl.get_choices()] for ID, cl in kernel.CHOICELISTS.items() } actions = set() for rpt in self.actors_list: # rh = rpt.get_handle() #for getting bound actor, not needed. for ba in rpt.get_actions(): if ba.action not in actions: actions.add(ba.action) self.serialise_js_code = True f.write( py2js( dict( actions={a.action_name: a for a in actions}, # actors={a.actor_id: a for a in self.actors_list}, menu=settings.SITE.get_site_menu(get_user_profile()), choicelists=choicelists_data, suggestors=list(settings.SITE.plugins.memo.parser. suggesters.keys()) # [#,@] keytriggers ), compact=not settings.SITE.is_demo_site)) self.serialise_js_code = False return 1
def grid_model_lines(rh): #~ yield "Ext.define('Lino.%s.GridModel',{" % rh.report #~ yield "extend: 'Ext.data.Model'," #~ yield "fields: %s," % py2js([js_code(f.as_js()) for f in rh.store.list_fields]) #~ yield "proxy: {" #~ yield " type: 'rest'," #~ yield " url : '%s'," % rh.ui.build_url(rh.report.app_label,rh.report._actor_name) #~ yield " format: 'json'" #~ yield " root: 'rows', " #~ yield "}" #~ yield "});" kw = dict() kw.update(extend='Ext.data.Model') kw.update(fields=[js_code(f.as_js()) for f in rh.store.list_fields]) kw.update(idProperty=rh.store.pk.name) kw.update(proxy=dict( type='rest', url = '/api' + rh.ui.build_url(rh.report.app_label,rh.report._actor_name), totalProperty="count", format='json', root='rows', reader='array', )) yield "Ext.define('Lino.%s.GridModel',%s);" % (rh.report,py2js(kw))
def js_render_ActionFormPanelSubclass(self, dh): tbl = dh.layout._datasource yield "" # yield "Lino.%s = Ext.extend(Lino.ActionFormPanel,{" % \ # dh.layout._formpanel_name yield "Ext.define('Lino.%s', { extend : 'Lino.ActionFormPanel'," % \ dh.layout._formpanel_name for k, v in list(dh.main.ext_options().items()): if k != 'items': yield " %s: %s," % (k, py2js(v)) assert tbl.action_name is not None # ~ raise Exception("20121009 action_name of %r is None" % tbl) yield " action_name: '%s'," % tbl.action_name yield " ls_url: %s," % py2js(dh.layout._url) yield " window_title: %s," % py2js(tbl.label) yield " before_row_edit : function(record) {" for ln in self.before_row_edit(dh.main): yield " " + ln yield " }," # ~ yield " layout: 'fit'," # ~ yield " auto_save: true," if dh.layout.window_size and dh.layout.window_size[1] == 'auto': yield " autoHeight: true," yield " initComponent : function() {" # 20140503 yield " var containing_panel = this;" lc = 0 for ln in jsgen.declare_vars(dh.main.elements): yield " " + ln lc += 1 yield " this.items = %s;" % py2js(dh.main.elements) yield " this.fields = %s;" % py2js([ e for e in dh.main.walk() if isinstance(e, ext_elems.FieldElement) ]) # yield " Lino.%s.superclass.initComponent.call(this);" % \ # dh.layout._formpanel_name yield " this.http_method = %s" % py2js(tbl.http_method) yield "this.callSuper();" yield " }" yield "});" yield ""
def get_head_lines(self, site, request): from lino.utils.jsgen import py2js if not self.site.use_websockets: return user_name = "anony" if request.user.authenticated: user_name = request.user.username site_title = site.title or 'Lino-framework' if not DJANGO2: js_to_add = (""" <script type="text/javascript"> Ext.onReady(function() { // Note that the path doesn't matter for routing; any WebSocket // connection gets bumped over to WebSocket consumers var ws_scheme = window.location.protocol == "https:" ? "wss" : "ws"; var ws_path = window.location.pathname + "lino/"; console.log("Connecting to " + ws_path); var webSocketBridge = new channels.WebSocketBridge(); var username = '******' ; webSocketBridge.connect(); lino_connecting = function() { console.log("lino connecting ..."); webSocketBridge.send({ "command": "user_connect", "username": username }); } webSocketBridge.socket.addEventListener('open', function() { lino_connecting(); }); // Helpful debugging webSocketBridge.socket.onclose = function () { console.log("Disconnected from chat socket"); } onGranted = console.log("onGranted"); onDenied = console.log("onDenied"); // Ask for permission if it's not already granted Push.Permission.request(onGranted,onDenied); webSocketBridge.listen(function(action, stream) { try { Push.create( %s , { body: action['body'], icon: '/static/img/lino-logo.png', onClick: function () { window.focus(); """ + site.kernel.default_renderer.reload_js() + """ this.close(); } }); if (false && Number.isInteger(action["id"])){ webSocketBridge.stream('lino').send({message_id: action["id"]}) webSocketBridge.send(JSON.stringify({ "command": "seen", "message_id": action["id"], })); } } catch(err) { console.log(err.message); } })}); // end of onReady()" </script> """) % (user_name, py2js(site_title)) else: js_to_add = (""" <script type="text/javascript"> Ext.onReady(function() { // Note that the path doesn't matter for routing; any WebSocket // connection gets bumped over to WebSocket consumers var ws_scheme = window.location.protocol == "https:" ? "wss" : "ws"; var ws_path = ws_scheme+ "://" + window.location.host + "/lino/"; console.log("Connecting to " + ws_path); var webSocketBridge = new WebSocket(ws_path); var username = '******' ; // webSocketBridge.connect(); lino_connecting = function() { console.log("lino connecting ..."); webSocketBridge.send({ "command": "user_connect", "username": username }); } //webSocketBridge.addEventListener('open', function() { // lino_connecting(); //}); // Helpful debugging webSocketBridge.onclose = function () { console.log("Disconnected from chat socket"); } onGranted = console.log("onGranted"); onDenied = console.log("onDenied"); // Ask for permission if it's not already granted Push.Permission.request(onGranted,onDenied); webSocketBridge.onmessage = function(e) { var data = e.data; Push.Permission.request(onGranted,onDenied); console.log("We get the message ",data); // var message = data['message']; try { Push.create( %s , { body: data, icon: '/static/img/lino-logo.png', onClick: function () { window.focus(); """ + site.kernel.default_renderer.reload_js() + """ this.close(); } }); if (false && Number.isInteger(action["id"])){ webSocketBridge.stream('lino').send({message_id: action["id"]}) webSocketBridge.send(JSON.stringify({ "command": "seen", "message_id": action["id"], })); } } catch(err) { console.log(err.message); } }}); // end of onReady()" </script> """) % (user_name, py2js(site_title)) yield js_to_add
def get_head_lines(self, site, request): if not self.site.use_websockets: return from lino.utils.jsgen import py2js user_name = "anony" if request.user.is_authenticated: user_name = request.user.username site_title = site.title or 'Lino-framework' if self.site.default_ui == 'lino_react.react': js_to_add = """ <script type="text/javascript"> window.Lino = window.Lino || {} window.Lino.useWebSockets = true; </script> """ else: js_to_add = (""" <script type="text/javascript"> Ext.onReady(function() { // Note that the path doesn't matter for routing; any WebSocket // connection gets bumped over to WebSocket consumers var ws_scheme = window.location.protocol == "https:" ? "wss" : "ws"; var ws_path = window.location.pathname + "lino/"; console.log("Connecting to " + ws_path); var webSocketBridge = new channels.WebSocketBridge(); var username = '******' ; webSocketBridge.connect(); lino_connecting = function() { console.log("lino connecting ..."); webSocketBridge.send({ "command": "user_connect", "username": username }); } webSocketBridge.socket.addEventListener('open', function() { lino_connecting(); }); // Helpful debugging webSocketBridge.socket.onclose = function () { console.log("Disconnected from chat socket"); } onGranted = console.log("onGranted"); onDenied = console.log("onDenied"); // Ask for permission if it's not already granted Push.Permission.request(onGranted,onDenied); webSocketBridge.listen(function(action, stream) { try { Push.create( %s , { body: action['body'], icon: '/static/img/lino-logo.png', onClick: function () { window.focus(); """ + site.kernel.default_renderer.reload_js() + """ this.close(); } }); if (false && Number.isInteger(action["id"])){ webSocketBridge.stream('lino').send({message_id: action["id"]}) webSocketBridge.send(JSON.stringify({ "command": "seen", "message_id": action["id"], })); } } catch(err) { console.log(err.message); } })}); // end of onReady()" </script> """) % (user_name, py2js(site_title)) yield js_to_add
def js_render_FormPanelSubclass(self, dh): tbl = dh.layout._datasource if not dh.main.get_view_permission(get_user_profile()): msg = "No view permission for main panel of %s :" % \ dh.layout._formpanel_name msg += " main requires %s (actor %s requires %s)" % ( dh.main.required_roles, tbl, tbl.required_roles) # ~ raise Exception(msg) logger.warning(msg) print(20150717, msg) return yield "" # yield "Lino.%s = Ext.extend(Lino.FormPanel,{" % \ # dh.layout._formpanel_name yield "Ext.define('Lino.%s', { extend : 'Lino.FormPanel'," % \ dh.layout._formpanel_name yield " layout: 'fit'," yield " auto_save: true," if dh.layout.window_size and dh.layout.window_size[1] == 'auto': yield " autoHeight: true," if settings.SITE.is_installed('contenttypes') and issubclass( tbl, dbtables.Table): yield " content_type: %s," % py2js( ContentType.objects.get_for_model(tbl.model).pk) if not tbl.editable: yield " disable_editing: true," if not tbl.auto_apply_params: yield " auto_apply_params: false," if dh.layout._formpanel_name.endswith('.InsertFormPanel'): yield " default_record_id: -99999," yield " initComponent : function() {" # 20140503 yield " var containing_panel = this;" # yield "// user user_type: %s" % jsgen._for_user_profile lc = 0 for ln in jsgen.declare_vars(dh.main): yield " " + ln lc += 1 if lc == 0: raise Exception("%r of %s has no variables" % (dh.main, dh)) yield " this.items = %s;" % dh.main.as_ext() # ~ if issubclass(tbl,tables.AbstractTable): if True: yield " this.before_row_edit = function(record) {" for ln in self.before_row_edit(dh.main): yield " " + ln yield " }" on_render = self.build_on_render(dh.main) if on_render: yield " this.onRender = function(ct, position) {" for ln in on_render: yield " " + ln yield " Lino.%s.superclass.onRender.call(this, ct, position);" % \ dh.layout._formpanel_name # yield " this.callSuper(ct, position);" yield " }" # yield " Lino.%s.superclass.initComponent.call(this);" % \ # dh.layout._formpanel_name yield " this.callSuper();" # Add a change listener to active fields. This which will # cause automatic form submit when some actiove field is # changed. if dh.layout._formpanel_name.endswith('.DetailFormPanel'): if tbl.active_fields: yield ' // active_fields:' for name in tbl.active_fields: e = dh.main.find_by_name(name) if e is not None: # 20120715 if True: # see actions.ValidateForm f = 'function(){ this.save() }' else: f = 'function(){ this.validate_form() }' yield ' %s.on("change", %s, this);' % (py2js(e), f) yield " }" yield "});" yield ""
def as_js(self): return py2js(self.options)
def get_field_options(self,**kw): kw = FieldElement.get_field_options(self,**kw) sto = self.store_options() #print repr(sto) kw.update(store=js_code("new Lino.ComplexRemoteComboStore(%s)" % py2js(sto))) return kw
def js_render_GridPanel_class(self, rh): yield "" yield "// js_render_GridPanel_class %s" % rh.actor # yield "Lino.%s.GridPanel = Ext.extend(Lino.GridPanel,{" % rh.actor yield "Ext.define('Lino.%s.GridPanel', { extend : 'Lino.GridPanel'," % rh.actor kw = dict() # ~ kw.update(empty_title=%s,rh.actor.get_button_label() if getattr(rh.actor, 'use_detail_params_value', None): kw.update(use_detail_params_value=True) kw.update(ls_url=rh.actor.actor_url()) kw.update(ls_store_fields=[ js_code(f.as_js(f.name)) for f in rh.store.list_fields ]) if rh.store.pk is not None: kw.update(ls_id_property=rh.store.pk.name) kw.update(pk_index=rh.store.pk_index) if settings.SITE.is_installed('contenttypes'): m = getattr(rh.store.pk, 'model', None) # e.g. pk may be the VALUE_FIELD of a choicelist which # has no model if m is not None: ct = ContentType.objects.get_for_model(m).pk kw.update(content_type=ct) kw.update(cell_edit=rh.actor.cell_edit) kw.update(ls_bbar_actions=self.toolbar( rh.actor.get_toolbar_actions(rh.actor.default_action.action))) kw.update(ls_grid_configs=[gc.data for gc in rh.actor.grid_configs]) kw.update(gc_name=constants.DEFAULT_GC_NAME) # ~ if action != rh.actor.default_action: # ~ kw.update(action_name=action.name) # ~ kw.update(content_type=rh.report.content_type) vc = dict(emptyText=_("No data to display.")) if rh.actor.editable: vc.update(getRowClass=js_code('Lino.getRowClass')) if rh.actor.auto_fit_column_widths: kw.update(forceFit=True) if rh.actor.variable_row_height: vc.update(cellTpl=js_code("Lino.auto_height_cell_template")) if rh.actor.row_height != 1: kw.update(row_height=rh.actor.row_height) tpl = """new Ext.Template( '<td class="x-grid3-col x-grid3-cell x-grid3-td-{id} {css}" style="{style}" tabIndex="0" {cellAttr}>', '<div class="x-grid3-cell-inner x-grid3-col-{id}" unselectable="on" style="height:%dpx" {attr}>{value}</div>', '</td>')""" % (rh.actor.row_height * 11) vc.update(cellTpl=js_code(tpl)) if rh.actor.drag_drop_sequenced_field is not None: vc.update( plugins={ 'ptype': 'gridviewdragdrop', 'dragText': 'Drag and drop to reorganize', 'sequenced_field': rh.actor.drag_drop_sequenced_field }) #todo get a field atrib also into the config somehow. kw.update(viewConfig=vc) if not rh.actor.editable: kw.update(disable_editing=True) if rh.actor.use_paging: kw.update(use_paging=True) if rh.actor.params_panel_hidden: kw.update(params_panel_hidden=True) if rh.actor.start_at_bottom: kw.update(start_at_bottom=True) kw.update(page_length=rh.actor.page_length) kw.update(stripeRows=True) # if rh.actor.label is not None: kw.update(title=rh.actor.label) if rh.actor.editable: kw.update( disabled_fields_index=rh.store.column_index('disabled_fields')) for k, v in kw.items(): yield " %s : %s," % (k, py2js(v)) yield " initComponent : function() {" a = rh.actor.detail_action if a: yield " this.ls_detail_handler = Lino.%s;" % a.full_name() a = rh.actor.insert_action if a: yield " this.ls_insert_handler = Lino.%s;" % a.full_name() yield " var ww = this.containing_window;" for ln in jsgen.declare_vars(rh.list_layout.main.columns): yield " " + ln yield " this.before_row_edit = function(record) {" for ln in self.before_row_edit(rh.list_layout.main): yield " " + ln yield " };" on_render = self.build_on_render(rh.list_layout.main) if on_render: yield " this.onRender = function(ct, position) {" for ln in on_render: yield " " + ln yield " Lino.%s.GridPanel.superclass.onRender.call(this, ct, position);" % rh.actor # yield "this.callSuper(ct, position);" yield " }" yield " this.ls_columns = %s;" % py2js([ ext_elems.GridColumn(rh.list_layout, i, e) for i, e in enumerate(rh.list_layout.main.columns) ]) # yield " Lino.%s.GridPanel.superclass.initComponent.call(this);" \ # % rh.actor yield "this.callSuper();" yield " }" yield "});" yield ""
def store_options(self,**kw): proxy = dict(url=self.lh.rh.ui.get_choices_url(self),method='GET') kw.update(proxy=js_code("new Ext.data.HttpProxy(%s)" % py2js(proxy))) # a JsonStore without explicit proxy sometimes used method POST return kw
def write(f): f.write(py2js(actor))
def js_render_window_action(self, rh, ba): # x = str(rh) # if x.startswith('working'): # print "20150421 {0}".format(x) # profile = get_user_profile() rpt = rh.actor if rpt.parameters and ba.action.use_param_panel: params_panel = rh.params_layout_handle else: params_panel = None if isinstance(ba.action, ShowDetail): mainPanelClass = "Lino.%sPanel" % ba.full_name() elif isinstance(ba.action, ShowInsert): mainPanelClass = "Lino.%sPanel" % ba.full_name() elif isinstance(ba.action, ShowTable): mainPanelClass = "Lino.%s.GridPanel" % rpt elif ba.action.parameters and not ba.action.no_params_window: params_panel = ba.action.make_params_layout_handle() elif ba.action.extjs_main_panel: pass else: # print "20150421 {0}".format(rh) return windowConfig = dict() wl = ba.get_window_layout() ws = ba.get_window_size() # ~ if wl is not None: # ~ ws = wl.window_size if True: if ws: windowConfig.update( # ~ width=ws[0], # width=js_code('Lino.chars2width(%d)' % ws[0]), maximized=False, draggable=True, maximizable=True, modal=True) # if isinstance(ws[0], basestring) and ws[0].endswith("%"): # windowConfig.update( # width=js_code('Lino.perc2width(%s)' % ws[0][:-1])) if isinstance(ws[0], str): windowConfig.update(width=ws[0]) else: windowConfig.update(width=js_code('Lino.chars2width(%d)' % ws[0])) if ws[1] == 'auto': # windowConfig.update(autoHeight=True) windowConfig.update(height=True) elif isinstance(ws[1], int): # ~ windowConfig.update(height=ws[1]) windowConfig.update(height=js_code('Lino.rows2height(%d)' % ws[1])) else: raise ValueError("height") # ~ print 20120629, action, windowConfig yield "Lino.%s = Ext.create('Lino.WindowAction',%s, function(){" % ( ba.full_name(), py2js(windowConfig)) # ~ yield " console.log('20120625 fn');" if ba.action.extjs_main_panel: yield " return %s;" % ba.action.extjs_main_panel else: p = dict() # if ba.action is settings.SITE.get_main_action(profile): # p.update(is_home_page=True) if ba.action.hide_top_toolbar or ba.actor.hide_top_toolbar or ba.action.parameters: p.update(hide_top_toolbar=True) if rpt.hide_window_title: p.update(hide_window_title=True) p.update(is_main_window=True) # workaround for problem 20111206 yield " var p = %s;" % py2js(p) if params_panel: if ba.action.parameters: yield " return Ext.create('Lino.%s',{});" % wl._formpanel_name else: yield " p.params_panel = Ext.create('Lino.%s',{});" % params_panel.layout._formpanel_name yield " return Ext.create('%s',{p});" % mainPanelClass else: yield " return Ext.create('%s',{p});" % mainPanelClass yield "});"
def js_render(self): yield "Lino.%s = function(caller) { " % self.action yield " return new Lino.%s(caller,%s);}" % ( self.__class__.__name__,py2js(self.config))
def __init__(self,lh,name,dv,**kw): #~ self.dv = dv #~ kw.update(tpl=js_code('new Ext.XTemplate(%s)' % py2js(dv.xtemplate))) kw.update(plugins=js_code('new Lino.TemplateBoxPlugin(caller,%s)' % py2js(dv.xtemplate))) LayoutElement.__init__(self,lh,name,**kw)