Committer: vtroitsky
LJSUP-10082: layeredit.bml moved to use Templates and WidgetsA trunk/cgi-bin/LJ/Widget/LayerEditor.pm U trunk/htdocs/customize/advanced/layeredit.bml
Added: trunk/cgi-bin/LJ/Widget/LayerEditor.pm =================================================================== --- trunk/cgi-bin/LJ/Widget/LayerEditor.pm (rev 0) +++ trunk/cgi-bin/LJ/Widget/LayerEditor.pm 2011-10-13 08:03:15 UTC (rev 20303) @@ -0,0 +1,230 @@ +package LJ::Widget::LayerEditor; + +use strict; +use base qw(LJ::Widget); +use Carp qw(croak); +sub ajax { 1 } +sub authas { 1 } +sub need_res { qw( stc/widgets/layereditor.css js/s2edit/xlib.js js/s2edit/s2edit.js js/s2edit/s2gui.js js/s2edit/s2parser.js js/s2edit/s2sense.js js/s2edit/s2library.js stc/s2edit.css) } + +=head2 template_filename +# path to template file, +# subclass may skip overriding this method +=cut +sub template_filename { + my $class = shift; + my $lc_class = lc $class->subclass; + $lc_class =~ s|::|/|g; + return "$ENV{'LJHOME'}/templates/Widgets/${lc_class}.tmpl"; +} + +=head2 render_body +=cut +# fully ready 'render_body' method, subclass have no need to override this method +sub render_body { + my $class = shift; + my %opts = @_; + + # opts: GET parameters, and from_post - from previous post, parameters + + my $filename = $class->template_filename(); + my $template = LJ::HTML::Template->new( + { use_expr => 1 }, # force HTML::Template::Pro with Expr support + filename => $filename, + die_on_bad_params => 0, + strict => 0, + ) or die "Can't open template '$filename': $!"; + + # template object already contains 'lj_siteroot' and several same parameters, look LJ/HTML/Template.pm + # also it contains 'ml', 'ljuser', ... functions + + my %params = ( ); + $class->prepare_template_params(\%params, %opts); + + if($opts{parameters}) { + $opts{parameters}->{$_} = $params{$_} foreach keys %params; + } + $template->param(%params); + + return if LJ::Request->redirected; + + return $template->output; +} + +=head2 prepare_template_params + +=cut +sub prepare_template_params { + my ($class, $params, %opts) = @_; + + use Data::Dumper; + warn "OPTS:".Dumper(\%opts); + + # we need a valid id + my $id = $opts{'id'} if $opts{'id'} =~ /^\d+$/; + die("You have not specified a layer to edit.") + unless $id; + + # authenticate user; + my $remote = LJ::get_remote(); + die("You must be logged in to edit layers.") + unless $remote; + + my $no_layer_edit = LJ::run_hook("no_theme_or_layer_edit", $remote); + die(BML::ml('/customize/advanced/index.bml.error.advanced.editing.denied')) + if $no_layer_edit; + + # load layer + my $lay = LJ::S2::load_layer($id); + die("The specified layer does not exist.") + unless $lay; + + # if the b2lid of this layer has been remapped to a new layerid + # then update the b2lid mapping for this layer + my $b2lid = $lay->{b2lid}; + if ($b2lid && $LJ::S2LID_REMAP{$b2lid}) { + LJ::S2::b2lid_remap($remote, $id, $b2lid); + $lay->{b2lid} = $LJ::S2LID_REMAP{$b2lid}; + } + + # is authorized admin for this layer? + die('You are not authorized to edit this layer.') + unless $remote && $remote->can_manage($lay->{'userid'}); + + # get u of user they are acting as + my $u = $lay->{'userid'} == $remote->{'userid'} ? $remote : LJ::load_userid($lay->{'userid'}); + + # check priv and ownership + croak("You are not authorized to edit styles.") + unless LJ::get_cap($u, "s2styles"); + + # at this point, they are authorized, allow viewing & editing + # get s2 code from db - use writer so we know it's up-to-date + my $dbh = LJ::get_db_writer(); + my $s2code = $opts{'s2code'} || LJ::S2::load_layer_source($lay->{s2lid}); + + # load layer info + my $layinf = {}; + LJ::S2::load_layer_info($layinf, [ $id ]); + + # find a title to display on this page + my $type = $layinf->{$id}->{'type'}; + my $name = $layinf->{$id}->{'name'}; + + # find name of parent layer if this is a child layer + if (! $name && $type =~ /^(user|theme|i18n)$/) { + my $par = $lay->{'b2lid'} + 0; + LJ::S2::load_layer_info($layinf, [$par]); + $name = $layinf->{$par}->{'name'}; + } + + # Only use the layer name if there is one and it's more than just whitespace + my $title = "[$type] "; + $title .= $name && $name =~ /[^\s]/ ? "$name [\#$id]" : "Layer \#$id"; + + # add template variables + $params->{prefix} = $class->input_prefix, + $params->{id} = $id; + $params->{type} = $type; + $params->{name} = $name; + $params->{title} = $title; + $params->{s2code} = LJ::ehtml($s2code); + $params->{s2doc} = "$LJ::SITEROOT/doc/s2", + $params->{build} = (exists $opts{build} ? $opts{build} : "Loaded layer $id."); + + $params->{is_remote_sup} = LJ::SUP->is_remote_sup ? 1 : 0; + $params->{errors} = [ $class->error_list ]; + $params->{form_auth} = LJ::form_auth(); + + return 1; +} +=head2 handle_post + Check parameters passed. + Compile layer, return compile status +=cut +sub handle_post { + my ($class, $post, %opts) = @_; + my $u = $class->get_effective_remote(); + my $build; + if ($post->{'action'} eq "compile") { + # we need a valid id + my $id = $post->{'id'} if $post->{'id'} =~ /^\d+$/; + + die("You have not specified a layer to edit.") unless $id; + + # load layer + my $lay = LJ::S2::load_layer($id); + die("The specified layer does not exist.") unless $lay; + + $build = "<b>S2 Compiler Output</b> <em>at " . scalar(localtime) . "</em><br />\n"; + + my $error; + $post->{'s2code'} =~ tr/\r//d; # just in case + unless (LJ::S2::layer_compile($lay, \$error, { 's2ref' => \$post->{'s2code'} })) { + + $error =~ s/LJ::S2,.+//s; + $error =~ s!, .+?(src/s2|cgi-bin)/!, !g; + + $build .= "Error compiling layer:\n<pre style=\"border-left: 1px red solid\">$error</pre>"; + + # display error with helpful context + if ($error =~ /^compile error: line (\d+)/i) { + my $errline = $1; + my $kill = $errline - 5 < 0 ? 0 : $errline - 5; + my $prehilite = $errline - 1 > 4 ? 4: $errline - 1; + my $snippet = $post->{'s2code'}; + + # make sure there's a newlilne at the end + chomp $snippet; + $snippet .= "\n"; + + # and now, fun with regular expressions + my $ct = 0; + $snippet =~ s!(.*?)\n!sprintf("%3d", ++$ct) . ": " . + $1 . "\n"!ge; # add line breaks and numbering + $snippet = LJ::ehtml($snippet); + $snippet =~ s!^((?:.*?\n){$kill,$kill}) # kill before relevant lines + ((?:.*?\n){$prehilite,$prehilite}) # capture context before error + (.*?\n){0,1} # capture error + ((?:.*?\n){0,4}) # capture context after error + .* # kill after relevant lines + !$2<em class='error'>$3</em>$4!sx; + + $build .= "<b>Context</b><br /><pre>$snippet</pre>\n"; + } + + } else { + $build .= "Compiled with no errors.\n"; + } + } + return ( build => $build, s2code => $post->{'s2code'} ); +} + +sub js { + q [ + initWidget: function () { + var self = this; + + var form = DOM.getElement("s2"); + DOM.addEventListener(form, "submit", function (evt) { self.warnWord(evt, form) }); + }, + warnWord: function (evt, form) { + var given_text = form["Widget[LayerEditor]_s2code"].value + ""; + + + this.doPostAndUpdateContent({ + s2code: given_text, + action: 'compile', + id: form["Widget[LayerEditor]_id"].value, + }); + + Event.stop(evt); + }, + onRefresh: function (data) { + this.initWidget(); + } + ]; + + +} +1; Modified: trunk/htdocs/customize/advanced/layeredit.bml =================================================================== --- trunk/htdocs/customize/advanced/layeredit.bml 2011-10-13 07:59:53 UTC (rev 20302) +++ trunk/htdocs/customize/advanced/layeredit.bml 2011-10-13 08:03:15 UTC (rev 20303) @@ -1,288 +1,30 @@ -<?_code # -*-bml-*- +<?_code { use strict; - our (%GET, %POST); + use vars qw(%POST %GET ); + use LJ::Widget::LayerEditor; + my %from_post = LJ::Widget->handle_post(\%POST, qw ( LayerEditor )); - # for error reporting - my $err = sub { - return "<title>Error</title>\n<h2>Error</h2>" . shift; - }; + my $widget = LJ::Widget::LayerEditor->new; - # we need a valid id - my $id = $GET{'id'} if $GET{'id'} =~ /^\d+$/; - return $err->("You have not specified a layer to edit.") - unless $id; + my %template_params; + $widget->prepare_template_params(\%template_params, %GET, %from_post); - # authenticate user; - my $remote = LJ::get_remote(); - return $err->("You must be logged in to edit layers.") - unless $remote; - - my $no_layer_edit = LJ::run_hook("no_theme_or_layer_edit", $remote); - return $err->($ML{'/customize/advanced/index.bml.error.advanced.editing.denied'}) - if $no_layer_edit; + my $filename = "$ENV{'LJHOME'}/templates/LayerEditor/layeredit.tmpl"; + my $template = LJ::HTML::Template->new( + { use_expr => 1 }, # force HTML::Template::Pro with Expr support + filename => $filename, + die_on_bad_params => 0, + strict => 0, + ) or die "Can't open template '$filename': $!"; - # load layer - my $lay = LJ::S2::load_layer($id); - return $err->("The specified layer does not exist.") - unless $lay; + $template->param(%template_params); - # if the b2lid of this layer has been remapped to a new layerid - # then update the b2lid mapping for this layer - my $b2lid = $lay->{b2lid}; - if ($b2lid && $LJ::S2LID_REMAP{$b2lid}) { - LJ::S2::b2lid_remap($remote, $id, $b2lid); - $lay->{b2lid} = $LJ::S2LID_REMAP{$b2lid}; - } + LJ::need_res($widget->need_res); + my $headextra = LJ::res_includes(); + $headextra .= $widget->wrapped_js(page_js_object => "LayerEditor"); + $template->param( headextra => $headextra); - # is authorized admin for this layer? - return $err->('You are not authorized to edit this layer.') - unless $remote && $remote->can_manage($lay->{'userid'}); - - # get u of user they are acting as - my $u = $lay->{'userid'} == $remote->{'userid'} ? $remote : LJ::load_userid($lay->{'userid'}); - - # check priv and ownership - return $err->("You are not authorized to edit styles.") - unless LJ::get_cap($u, "s2styles"); - - # at this point, they are authorized, allow viewing & editing - - # get s2 code from db - use writer so we know it's up-to-date - my $dbh = LJ::get_db_writer(); - my $s2code = $POST{'s2code'} || LJ::S2::load_layer_source($lay->{s2lid}); - - # we tried to compile something - my $build; - if ($POST{'action'} eq "compile") { - return "<b>$ML{'Error'}</b> $ML{'error.invalidform'}" unless LJ::check_form_auth(); - - $build = "<b>S2 Compiler Output</b> <em>at " . scalar(localtime) . "</em><br />\n"; - - my $error; - $POST{'s2code'} =~ tr/\r//d; # just in case - unless (LJ::S2::layer_compile($lay, \$error, { 's2ref' => \$POST{'s2code'} })) { - - $error =~ s/LJ::S2,.+//s; - $error =~ s!, .+?(src/s2|cgi-bin)/!, !g; - - $build .= "Error compiling layer:\n<pre style=\"border-left: 1px red solid\">$error</pre>"; - - # display error with helpful context - if ($error =~ /^compile error: line (\d+)/i) { - my $errline = $1; - my $kill = $errline - 5 < 0 ? 0 : $errline - 5; - my $prehilite = $errline - 1 > 4 ? 4: $errline - 1; - my $snippet = $s2code; - - # make sure there's a newlilne at the end - chomp $snippet; - $snippet .= "\n"; - - # and now, fun with regular expressions - my $ct = 0; - $snippet =~ s!(.*?)\n!sprintf("%3d", ++$ct) . ": " . - $1 . "\n"!ge; # add line breaks and numbering - $snippet = LJ::ehtml($snippet); - $snippet =~ s!^((?:.*?\n){$kill,$kill}) # kill before relevant lines - ((?:.*?\n){$prehilite,$prehilite}) # capture context before error - (.*?\n){0,1} # capture error - ((?:.*?\n){0,4}) # capture context after error - .* # kill after relevant lines - !$2<em class='error'>$3</em>$4!sx; - - $build .= "<b>Context</b><br /><pre>$snippet</pre>\n"; - } - - } else { - $build .= "Compiled with no errors.\n"; - } - } else { - $build = "Loaded layer $id."; - } - - # load layer info - my $layinf = {}; - LJ::S2::load_layer_info($layinf, [ $id ]); - - # find a title to display on this page - my $type = $layinf->{$id}->{'type'}; - my $name = $layinf->{$id}->{'name'}; - - # find name of parent layer if this is a child layer - if (! $name && $type =~ /^(user|theme|i18n)$/) { - my $par = $lay->{'b2lid'} + 0; - LJ::S2::load_layer_info($layinf, [$par]); - $name = $layinf->{$par}->{'name'}; - } - - # Only use the layer name if there is one and it's more than just whitespace - my $title = "[$type] "; - $title .= $name && $name =~ /[^\s]/ ? "$name [\#$id]" : "Layer \#$id"; - - LJ::need_res( 'js/s2edit/xlib.js', - 'js/s2edit/s2edit.js', - 'js/s2edit/s2gui.js', - 'js/s2edit/s2parser.js', - 'js/s2edit/s2sense.js', - 'js/s2edit/s2library.js', - 'stc/s2edit.css'); - - my $includes = LJ::res_includes(); - my $formauth = LJ::form_auth(); - - # ------------------------------------------------------------------------- - # S2 Editor HTML follows - # ------------------------------------------------------------------------- - - return <<HERE; -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml"> -<head> -<title>$title - S2 Designer</title> - -<script type="text/javascript"><!-- - var s2docBaseURL = "$LJ::SITEROOT/doc/s2"; -// --> -</script> - -$includes - -<!--[if IE]> -<style type="text/css"> - html { - overflow: hidden; - } - - div.reference { - height: expression(xGetElementById('statusbar').offsetTop - (42 + 9 + 10) + "px"); - } - - div.output { - width: expression(xGetElementById('statusbar').clientWidth - (18 + xGetElementById('out').offsetLeft) + "px"); - bottom: 45px; - } - - div.divider { - font-size: 2px; - } - - #outputdivider { - width: expression(xGetElementById('statusbar').clientWidth - (18 + xGetElementById('out').offsetLeft) + "px"); - bottom: 145px; - height: 7px; - } - - #refdivider { - height: expression(xGetElementById('statusbar').offsetTop - (42 + 9 + 10) + "px"); - } - - div.main { - width: expression(xGetElementById('statusbar').clientWidth - (18 + 6 + xGetElementById('out').offsetLeft) + "px"); - height: expression(xGetElementById('statusbar').offsetTop - (42 - 16 + xGetElementById('out').clientHeight + 57) + "px"); - } - - textarea.maintext { - width: 100%; - height: expression(xGetElementById('statusbar').offsetTop - (42 - 16 + xGetElementById('out').clientHeight + 57) + "px"); - } - - #outputtabs { - width: expression(xGetElementById('statusbar').clientWidth - (18 + 4 + xGetElementById('out').offsetLeft) + "px"); - } -</style> -<![endif]--> - -</head> -<body onMouseMove="s2processDrag(event)" onMouseUp="s2endDrag(event)"> - <form method="post" name="s2" action="" onsubmit="return s2submit()"> - $formauth - <input type="hidden" name="action" value="compile" /> - - <div class="header"> - <h1>$title</h1> - - <div class="tools"> - <a href="$LJ::SITEROOT/doc/s2" target="_blank">Documentation</a> - </div> - - <input type="submit" value="Save & Compile" class="compilelink" /> - </div> - - <div class="main" id="maindiv"> - <div class="maincontainer"> - <textarea id="main" class="maintext" name="s2code" onKeyPress="s2keyPressed(event)" wrap="off" - onKeyDown="s2IETabKeyPressedHandler(event)">@{[ LJ::ehtml($s2code) ]}</textarea> - </div> - </div> - <div class="divider" id="outputdivider" onMouseDown="s2startDrag(event)" - onMouseUp="s2endDrag(event)" - onMouseMove="s2processDrag(event)"> </div> - <div class="tabs" id="outputtabs"> - <h2>Build</h2> - </div> - <div id="out" class="output"> - $build - </div> - - <div class="tabs" id="reftabs"> - <span id="navtabs" class="refvisible"> - <h2>Nav.</h2> - <a href="javascript:s2switchRefTab(0)">Classes</a> - <a href="javascript:s2switchRefTab(1)">Funcs.</a> - <a href="javascript:s2switchRefTab(2)">Props.</a> - </span> - <span id="classtabs" class="refinvisible"> - <a href="javascript:s2switchRefTab(-1)">Nav.</a> - <h2>Classes</h2> - <a href="javascript:s2switchRefTab(1)">Funcs.</a> - <a href="javascript:s2switchRefTab(2)">Props.</a> - </span> - <span id="functabs" class="refinvisible"> - <a href="javascript:s2switchRefTab(-1)">Nav.</a> - <a href="javascript:s2switchRefTab(0)">Classes</a> - <h2>Funcs.</h2> - <a href="javascript:s2switchRefTab(2)">Props.</a> - </span> - <span id="proptabs" class="refinvisible"> - <a href="javascript:s2switchRefTab(-1)">Nav.</a> - <a href="javascript:s2switchRefTab(0)">Classes</a> - <a href="javascript:s2switchRefTab(1)">Funcs.</a> - <h2>Props.</h2> - </span> - </div> - <div id="ref" class="reference"> - <div id="nav" class="refvisible"> - - </div> - <div id="classref" class="refinvisible"> - (Classes) - </div> - <div id="funcref" class="refinvisible"> - (Functions) - </div> - <div id="propref" class="refinvisible"> - (Properties) - </div> - </div> - - <div class="divider" id="refdivider" onMouseDown="s2startDragRef(event)" - onMouseUp="s2endDrag(event)" - onMouseMove="s2processDrag(event)"> </div> - - <div class="statusbar" id="statusbar"> - <div class="gutter"> </div> - <div id="status">Ready.</div> - </div> - - </form> - - -</body> -</html> - - - -HERE + return $template->output; } _code?>