Chandra
view release on metacpan or search on metacpan
SV *
fields(self)
SV *self
CODE:
{
HV *hv = (HV *)SvRV(self);
SV **fields_svp = hv_fetchs(hv, "_fields", 0);
AV *fields = (AV *)SvRV(*fields_svp);
AV *names = newAV();
I32 i, len = av_len(fields);
for (i = 0; i <= len; i++) {
SV **fref = av_fetch(fields, i, 0);
if (fref && SvROK(*fref)) {
HV *fhv = (HV *)SvRV(*fref);
SV **n = hv_fetchs(fhv, "name", 0);
if (n && SvOK(*n))
av_push(names, newSVsv(*n));
}
}
RETVAL = newRV_noinc((SV *)names);
}
OUTPUT:
RETVAL
# ---- action(coderef) - get/set action handler ----
SV *
action(self, ...)
SV *self
CODE:
{
HV *hv = (HV *)SvRV(self);
if (items > 1) {
if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVCV)
croak("action() requires a coderef");
(void)hv_stores(hv, "_action", newSVsv(ST(1)));
RETVAL = SvREFCNT_inc(self);
} else {
SV **act = hv_fetchs(hv, "_action", 0);
RETVAL = (act && SvOK(*act)) ? newSVsv(*act) : &PL_sv_undef;
}
}
OUTPUT:
RETVAL
# ---- dispatch(event_type, json_string) - internal: called from bridge ----
void
dispatch(self, event_type, json_str)
SV *self
SV *event_type
SV *json_str
CODE:
{
HV *hv = (HV *)SvRV(self);
const char *evt = SvPV_nolen(event_type);
SV *decoded;
/* Decode JSON */
{
dSP;
int count;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(json_str);
PUTBACK;
count = call_pv("Cpanel::JSON::XS::decode_json", G_SCALAR | G_EVAL);
SPAGAIN;
if (SvTRUE(ERRSV) || count < 1) {
PUTBACK;
FREETMPS;
LEAVE;
return;
}
decoded = (count == 1) ? SvREFCNT_inc(POPs) : NULL;
PUTBACK;
FREETMPS;
LEAVE;
}
if (!decoded || !SvROK(decoded) || SvTYPE(SvRV(decoded)) != SVt_PVHV) {
if (decoded) SvREFCNT_dec(decoded);
return;
}
if (strEQ(evt, "_form_submit")) {
SV **act = hv_fetchs(hv, "_action", 0);
if (act && SvROK(*act) && SvTYPE(SvRV(*act)) == SVt_PVCV) {
HV *dhv = (HV *)SvRV(decoded);
SV **data_svp = hv_fetchs(dhv, "data", 0);
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(data_svp ? *data_svp : &PL_sv_undef);
PUTBACK;
call_sv(*act, G_DISCARD);
FREETMPS;
LEAVE;
}
} else if (strEQ(evt, "_form_change") || strEQ(evt, "_form_input")) {
HV *dhv = (HV *)SvRV(decoded);
SV **field_svp = hv_fetchs(dhv, "field", 0);
SV **value_svp = hv_fetchs(dhv, "value", 0);
if (field_svp && SvOK(*field_svp)) {
STRLEN flen;
const char *fname = SvPV(*field_svp, flen);
/* Field-specific handler */
{
SV **oc_svp = hv_fetchs(hv, "_on_change", 0);
if (oc_svp && SvROK(*oc_svp)) {
HV *oc_hv = (HV *)SvRV(*oc_svp);
SV **cb = hv_fetch(oc_hv, fname, flen, 0);
if (cb && SvROK(*cb) && SvTYPE(SvRV(*cb)) == SVt_PVCV) {
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(value_svp ? *value_svp : &PL_sv_undef);
PUTBACK;
call_sv(*cb, G_DISCARD);
FREETMPS;
LEAVE;
}
}
}
/* Global on_change handler */
{
SV **gcb = hv_fetchs(hv, "_on_change_global", 0);
if (gcb && SvROK(*gcb) && SvTYPE(SvRV(*gcb)) == SVt_PVCV) {
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(*field_svp);
XPUSHs(value_svp ? *value_svp : &PL_sv_undef);
PUTBACK;
call_sv(*gcb, G_DISCARD);
FREETMPS;
LEAVE;
}
}
}
} else if (strEQ(evt, "_form_values")) {
SV **cb = hv_fetchs(hv, "_get_values_cb", 0);
if (cb && SvROK(*cb) && SvTYPE(SvRV(*cb)) == SVt_PVCV) {
HV *dhv = (HV *)SvRV(decoded);
SV **data_svp = hv_fetchs(dhv, "data", 0);
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(data_svp ? *data_svp : &PL_sv_undef);
PUTBACK;
call_sv(*cb, G_DISCARD);
FREETMPS;
LEAVE;
(void)hv_stores(hv, "_get_values_cb", &PL_sv_undef);
}
}
SvREFCNT_dec(decoded);
}
# ---- _route_event(event_type, json_str) - class method: routes to correct form ----
void
_route_event(class, event_type, json_str)
const char *class
SV *event_type
SV *json_str
CODE:
{
SV *decoded;
PERL_UNUSED_VAR(class);
/* Decode JSON to extract the form id */
{
dSP;
int count;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(json_str);
PUTBACK;
count = call_pv("Cpanel::JSON::XS::decode_json", G_SCALAR | G_EVAL);
SPAGAIN;
if (SvTRUE(ERRSV) || count < 1) {
PUTBACK;
FREETMPS;
LEAVE;
return;
}
decoded = (count == 1) ? SvREFCNT_inc(POPs) : NULL;
PUTBACK;
FREETMPS;
LEAVE;
}
if (!decoded || !SvROK(decoded) || SvTYPE(SvRV(decoded)) != SVt_PVHV) {
if (decoded) SvREFCNT_dec(decoded);
return;
}
/* Extract id from the decoded hash */
{
HV *dhv = (HV *)SvRV(decoded);
SV **id_svp = hv_fetchs(dhv, "id", 0);
if (id_svp && SvOK(*id_svp)) {
STRLEN id_len;
const char *id = SvPV(*id_svp, id_len);
SV *form = _form_lookup(aTHX_ id, id_len);
if (form) {
/* Call $form->dispatch($event_type, $json_str) */
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(form);
XPUSHs(event_type);
XPUSHs(json_str);
PUTBACK;
call_method("dispatch", G_DISCARD);
FREETMPS;
LEAVE;
}
}
}
SvREFCNT_dec(decoded);
}
# ---- attach(app) - register form and bind events on the app ----
SV *
attach(self, app)
SV *self
SV *app
CODE:
{
HV *hv = (HV *)SvRV(self);
SV **id_svp = hv_fetchs(hv, "id", 0);
STRLEN id_len;
const char *id;
if (!id_svp || !SvOK(*id_svp))
croak("attach(): form has no id");
id = SvPV(*id_svp, id_len);
/* Register this form in the global registry */
_form_register(aTHX_ id, id_len, self);
/* Bind the four form events on the app (once globally) */
if (!_form_events_bound) {
static const char *events[] = {
"_form_submit", "_form_change", "_form_input", "_form_values"
};
int i;
for (i = 0; i < 4; i++) {
dSP;
SV *evt_name = sv_2mortal(newSVpv(events[i], 0));
SV *evt_copy = newSVpv(events[i], 0);
/* Build a closure: sub { Chandra::Form->_route_event('evt', $_[0]); 1 } */
SV *cb;
{
SV *code_str = sv_2mortal(newSVpvf(
"sub { Chandra::Form->_route_event('%s', $_[0]); 1 }",
events[i]));
cb = eval_pv(SvPV_nolen(code_str), TRUE);
SvREFCNT_inc(cb);
}
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(app);
XPUSHs(evt_name);
XPUSHs(sv_2mortal(newRV_noinc(cb)));
PUTBACK;
call_method("bind", G_DISCARD);
FREETMPS;
LEAVE;
SvREFCNT_dec(evt_copy);
}
_form_events_bound = 1;
}
/* Inject the bind_js for this form */
( run in 0.839 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )