API o ztag - noradle/plsql-print GitHub Wiki

o(ztag) API 设计

命名含义

ztag 代表

  • z 最后一个字母,代表终极设计
  • z 代表zip压缩,代表该API设计极致简洁

o 是 ztag 的同义词,代表

  • output API
  • o 是字母表中的中值,代表它在 noradle 中,处于中心地位
  • o 代表圆滑、均衡,寓意为该 API 设计既简洁但又非常灵活
  • noradle 代码中,单个字母做 API 包名的只剩下,N,O,Q,S,O最合适

各特性使用概率估计:

  1. 绝大部分都是写死字符串
  2. 不写死字符串的基本上都是 "url" or "form value",都有专门的特化API支持
  • form.action
  • base|link|a.href
  • script|img|iframe|frame.src
  • input.value.checked
  • option.value.selected
  1. 其他情形几乎就很少用到了,万一使用,用?标识
  • 待变量替换的位置
  • 开关决定的位置

design priciple

  • 模板串可以完全是网站粘来html片段,不改也能直接用,然后一点点的concise化
  • 支持和符合 html5 标准
  • 不能损失对底层的控制
  • 所有经常需要用变量而不是死字符串的属性,都要追加API并提供对应参数
  • 其他属性如果要使用变量控制或者boolean控制存在,都要使用 tmp.p(idx):=val 来准备参数,无需带入 st 类型参数这么麻烦
  • ? 代表 boolean 判断还是替换,看?前的字符串
    • 如果是 =就是替换
    • 如果是空是替换
    • 其他情形都是
    • x.v('<input.glyficon?.glyficon-? checked? readonly? -bind=xxx p1=? p2=?/>', value, true);
    • xxx? 对应值为 true 保留, false 或者null,就清除不要
    • ? 前是
    • +xxx? 对应值为 true 或者 null,都保留
  • 复杂的值,可能带有空格" "或等号"=",造成分段错误(中间分段)或者替换错误(多次替换),必须用""引起来
    • class
    • style: 如 style=1px solid red;
    • onevent: 如 onclick=a=b
    • -bind: 如 data-bind={a:1,b:2} or 内含 js 代码,knockout.js 会有这种情况
    • ng-xxx
    • style: inline style 全部可以用带有语义的 class 替代,然后配置该 css 的样式
    • onevent: 本来就应该通过 el.on('event') 或 jquery $("#id").on 来实现

APIs

o.t 基础标签输出

不再对标签的打开、关闭、自关闭、带内容关闭单独设计 API

  • < 结束代表open
  • >, text 代表 open/close
  • /> 结束代表自关闭
  • </ 代表 close
  • >n 代表替换从 tmp.p(n)开始替换?
  • 无 < 代表是 plain text
o.t('<div>'); -- open tag
o.t('</div>'); -- close tag
o.t('<div.class1? editable? -bind=?>?', text); -- open/close tag with innerText
o.t('<img alt=text/>'); -- self-closed tag
o.t('  text');  -- plain text without text

o.u 输出属性取值为url类型的标签

在o.t基础上增加url参数

o.u('<meta/>', url)
o.u('<link rel=stylesheet/>', url)
o.u('<script>', url, '')
o.u('<iframe>', url, '')
o.u('<frame>', url, '')
o.u('<img/>', url)
o.u('<a>', url, text)
o.u('<a>', url)
o.u('<form>', url)

o.v 输出带有value属性,并且可选含有是否选中的参数

o.v('<option>', value, text, false)
o.v('<input/>', value, true)

o.p(idx, value) 提供待定参数值

* o.p(1, 'varchar2');  -- varchar2
* o.p(2, true); -- boolean
* o.p(3, 123); -- number

o.c(comment) 输出注释

输出 <!--comment--> html 注释

o.d($$plsql_unit, $$plsql_line) 输出 debug

在注释中输出 debug 信息,包含代码所在的程序单元名称和行号,如 <!--@Z_TEST_B:64-->

substitude rule

范例

* o.t('<tag#id?>')
* o.t('<tag.collapse.in?>') in? 控制是否包含
* o.t('<tag.glyphicon.glyphicon-?>') -?直接追加
* o.t('<tag.glyph?>'); 控制是否包含 class glyph
* o.t('<tag.glyph-?>'); 在 glyph- 的基础上追加后面的部分,只要?前不是字母数字
* o.t('<tag.glyph+?>'); 在 glyph 的基础上追加后面的部分,+ 去除
* o.t('<tag checked? disabled? -?>') -? 追加形如 data-xxx
* o.t('<tag width=? title=xxx?xx?x>') 非法,属性值只能是静态串或者是?来替换,?只有在区段最后才代表替换或开关
* o.t('<tag style="border: 1px solid">')
* o.t('<tag.alert.alert-? width=?>')
* o.t('<p.alert?.alert-?.?.right_class?wrong_class?>') 正常应该是设置判断,但是如果前字符没有或者是分割符-,则代表是替换
* o.t('<tag.glyphicon.glyphicon-? checked? selected? width=?>')

规则

  • 对于 id,class,bool 只看最后的?
    • 字母数字后面?都是开关,开关参数为真则保留,否则忽略不输出
    • 非字母数字后面?都代表追加,因为class名称不可能是 none-alpha-digital 结尾
    • +? 特殊,代表追加内容,但是不包含+本身,用于直接将字母数字结束的名称后面直接追加字符串,否则?只能代表开关
  • 对于 name=value 的
    • value 可以不能包含任意多个?用于替换,z 只看最后字符是否是?,是则替换
    • 如果 value 中间本来就包含?那么也可以照常书写,不必放到替换值中
  • 从性能的角度考虑,每段落只能在最后一个字符写?
    • 分析完每个段落后,只看该段落最后是否有?,有则使用参数控制或替换,没有就认为无参数对应

参数如何提供

替换参数选择,建议一行设置一个替换参数,这样代码比较清晰

直接使用 assosiate array

  • tmp.p(1) := 'string';
  • tmp.p(2) := 123;
  • tmp.p(3) := t.tf(boolean)

这样代码比较简练,省去了子过程子函数调用,开销更小,速度更快

使用 o.p,内部用 assosiate array tmp.p

  • o.p(1, 'varchar2'); -- varchar2
  • o.p(2, true); -- boolean
  • o.p(3, 123); -- number

这样代码最为简练,而且可以用同一规格设定 varchar2,boolean,number 三种类型的代定参数值

从指定下标的 tmp.p(idx) 做替换值

o.t('<tag.class1?>3') 代表从 idx=3 的 tmp.p 开始取用于替换的值,而不是默认的1

和原来版本的主要区别

和 tag API 一样,依然要按照 tag, #id, .class, bool, name=value 的顺序书写标签

keep html but shorter, and easy to fill dynamic data

更直观、更简洁、更灵活

  1. 合并 API,更简单,更容易掌握
  • API 命名都是一个字母,嵌入plsql中的html代码更容易对齐
  • x.o, x.c, x.s, x.p 合并成 z.t,靠 <tag> <tag/> </tag> 和是否有 innerText 参数来区分
  • x.j, x.l, x.b, x.f, x.i 合并成了 z.u(tag, url)
  • x.bool 系列的 API 去除
  • 根据标签自行决定 url 采用哪个属性,src,href,action
  • 根据标签自行决定选择状态采用哪个属性,checked,selected
  1. 更符合标准 html 语法
  • data-xxx 原来简写是 ^xxx,现在简写是 -xxx,也就是没有 data 前缀,-前缀就认为是 data-
  • 属性值可以用双引号括起来,也没关系,对于内容中有空格和特殊字符的情况必须要括起来
  • 直接粘贴 html 代码,前面添加 b.l(' ') 即可使用
  • 然后改成 o.t, o.u, o.v 进行简化
  • 系统提供转换工具,自动将每行的 b.l(' ') 转换成 x API
  1. 待定参数简化并且增强功能
  • 待定参数不用放到 API 调用中,提前在 tmp.p(idx) := value 中准备,代码更清晰
  • 可读性更强:全部属性都放在首参数串中,所有待定无论存在还是替换都用?
  • 也可以使用 o.p(idx, value) 来准备替换参数值
  • 在 tag 模板串中指示是否需要用到动态参数,而不是原来的看参数st是否存在
  • 替换变量不用带入 api,模板中各部分末尾带有?的,自动去 tmp.p(idx) 中去替换参数值
  • 替换变量不再使用 :n,而改为使用 ?,更简单,带入参数顺序必须和模板保持一致
  • <...>n 中可以指定从 tmp.p 中的下标为n开始查找替换变量,而不是默认的1
  • 不仅支持替换,还支持是否保留的控制

综合范例

create or replace package body z_test_b is

	procedure d is
	begin
		r.setc('l$', '/static/');
		r.setc('l$jquery.js', '//cdn.bootcss.com/jquery/2.1.4/jquery.min.js');
		r.setc('l$bootstrap.css', '//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css');
	
		b.l('<!DOCTYPE html>');
		o.t('<html>');
		o.t('<head>');
		o.u(' <base target=_blank/>', '^js/test.js');
		o.u(' <script>', '[jquery.js]', '');
		o.u(' <link rel=stylesheet/>', '[bootstrap.css]');
		o.t('</head>');
		o.t('<body>');
	
		o.t('<script type=text>');
		o.u(' <frame>', './pack_b.proc', '');
		o.u(' <iframe>', './pack_b.proc', '');
		o.t('</script>');
	
		o.u('<a target=window1 title=linktest>', './pack_b.proc', 'inner text');
		o.u('<a>', './pack_b.proc');
		x.t(' wrapped text');
		o.u(' <img/>', '^img/banner.jpg');
		o.t('</a>');
	
		o.u('<form name=f1 method=post>', '@c.d');
		o.v(' <input name=n1 type=text/>', 'value1');
		o.v(' <input name=n2 type=checkbox/>', 'o1', true);
		o.v(' <input name=n2 type=checkbox/>', 'o2', false);
		o.v(' <input name=n2 type=checkbox/>', 'o3');
		o.t(' <label>', o.v('<input name=r type=radio/>', 'r1') || 'item1');
		o.t(' <label>', o.v('<input name=r type=radio/>', 'r2', true) || 'item2');
		o.t(' <label>', o.v('<input name=r type=radio/>', 'r3', false) || 'item3');
		o.t(' <select multiple name=n3>');
		o.v('  <option>', 'v1', 'text1');
		o.v('  <option>', 'v2', 'text2', true);
		o.v('  <option>', 'v3', 'text3', false);
		o.t(' </select>');
		o.t('</form>');
	
		tmp.p(1) := t.tf(false);
		tmp.p(2) := t.tf(false);
		tmp.p(3) := 'info';
		o.t('<div#container?.bg-info?.alert.alert-?>', 'inner text');
	
		tmp.p(1) := t.tf(false);
		tmp.p(2) := t.tf(false);
		tmp.p(3) := t.tf(true);
		tmp.p(4) := 'flag-pass';
		tmp.p(5) := 'defer';
		o.t('<div checked? readonly disabled? -ok? -? ?>', 'inner text');
	
		o.p(1, 600);
		o.p(2, 'click:func1');
		o.t('  <div width=400 height=? style="border:1px solid red;" -bind=?>');
		o.t('  </div>');
	
		o.t('</body>');
		o.t('</html>');
	end;

end z_test_b;
⚠️ **GitHub.com Fallback** ⚠️