CMS:文章管理之视图(3)
因为Combobox中返回的是一个完整的树,其节点全部是展开的,因而可以知道,展开后的节点的图标是模拟效果所需的。将Firebug切换到HTML面板,然后单击选择页面元素的按钮,选择展开后的那个黑色小三角图标,在Firebug中会看到如图54中的效果。
Grocery List节点的构成是2个图标加上文字。现在要做的就是把两个图标的HTML代码复制出来。接着选择Coffee节点,会看到它是由3个空白图标、1个叶子图标、1个复选框和文字构成的,这里面的空白图标和叶子图标也是需要的,复制出来。
从书中可以知道,这些图标src中的图片都是空白图片,起占位符的作用,实际显示的是它们的背景图片。(这也说明,这个在IE旧版本中是没有效果的)
在HTML面板中,选中这些图片,然后在右边的样式中就可看到它们的样式了,选择叶子图标,会看它主要由2个样式决定显示方式。第1个就是顶部的img的样式,这个很重要,如果没有该样式,图标和文字就不能对齐,会上下错位。第2个样式“x-tree-icon-leaf”了,它用来显示背景图片。
笔者测试过,直接保留样式和整个结构搬过去并不行,还是要重新定义一下样式。因为Ext.view.BoundList的每个列表行的起始样式是x-boundlist-item,因而从这个样式开始重新定义一下样式就行了。切换到app.css,添加以下样式:
.x-boundlist-item span
{
line-height:19px;
}
.x-boundlist-item img
{
display:inline;
vertical-align: top;
}
.x-boundlist-item .x-tree-elbow-plus
{
background-image:url("../../../extjs/resources/themes/images/default/tree/arrows.gif");
background-position: -16px 0;
width:16px;
}
.x-boundlist-item .x-tree-icon-parent {
background-image:url("../../../extjs/resources/themes/images/default/tree/folder-open.gif");
width:16px;
}
.x-boundlist-item .x-tree-icon-leaf
{
background-image: url("../../../extjs/resources/themes/images/default/tree/leaf.gif");
width:16px;
}
第1个样式是为文字对齐用的,如果不套一个span,直接设置x-boundlist-item的line-height,会影响其它的Combobox,因而这里套一个span来对齐文字。第2个样式是用来定义图标显示方式的;第3个用来显示展开的小三角图标;第4个用来显示打开的文件夹图标;第6个用来显示叶子图标,也就是在图55看到的样式。
现在切换到Category控制器,先新增几个私有变量来指定图片,代码如下:
private string blank = "<imgclass='x-tree-elbow'src='data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='>";
private string folder = "<imgclass='x-tree-icon x-tree-icon-parent ' src='data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='>";
private string leaf = "<imgclass='x-tree-icon x-tree-icon-leaf'src='data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='>";
private string plus = "<img class='x-tree-elbow-plusx-tree-expander'src='data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='>";
重载一个writeNode方法来生成新的数据结构,代码如下:
private JObject writeNode(int id, string text, boolisLeaf, int level)
{
stringoffset= "";
if(level>0)
{
offset = string.Join(string.Empty, Enumerable.Repeat(blank,level).ToArray());
}
stringlistText = "<span>" + offset + (isLeaf ? blank + leaf : plus+folder)+text +"</span>";
JObjectjo = new JObject
{
newJProperty("id",id),
newJProperty("text",text),
newJProperty("listText",listText)
};
returnjo;
}
因为两个writeNode参数相同,且参数类型也一样,因而第2个方法把3和4参数对调了一下。参数level的作用就是用来生成空白图标的。
Enumerable对象的Repeat方法可生成一个重复值的队列,非常方便。把队列转换为数组,就可通过字符串的Join方法将数组转换为字符串了。
用来显示的listText,先套一个span,然后加上偏移量,也就是空白图标。如果是叶子,就加多一个空白图标,再加上叶子图标。如果不是叶子,就加一个展开的小三角图标和打开的文件夹图标。最后加上文本。
CategoryCombo提交的是All方法,现在完成All方法,代码如下:
public JObject All()
{
boolsuccess = false;
stringmsg = "";
JArray ja= new JArray();
int total= 0;
try
{
ja.Add(writeNode(-1,"文章类别",false,0));
ja.Add(writeNode(10000, "未分类", true, 1));
var q = dc.T_Category.Where(m =>m.State == 0 & m.CategoryId!=10000).OrderBy(m => m.FullPath);
foreach (var c in q)
{
bool leaf = c.Childs.Count() > 0 ? false : true;
ja.Add(writeNode(c.CategoryId, c.Title, leaf,(int)c.Hierarchylevel+1));
}
success = true;
}
catch(Exception e)
{
msg =e.Message;
}
returnHelper.MyFunction.WriteJObjectResult(success, total, msg, ja);
}
还是重复得不能再重复的代码。因为有全路径,因而通过FullPath排序就可直接把树排列好了。这里还是要先把“未分类”排除在外,让它显示在前面。因为要把根目录显示出来,因而要多添加一个“文章分类”作为根。也因为根目录才是第1层,而Hierarchylevel是以没有父id的列为根的,因而要加1。
生成一下解决方案,然后展开父类选择,
定义父类的Combobox时,忘记加上查询功能了,只要添加配置项queryMode,值为local就行了。因为是必选的,因而,还要加上forceSelection配置项,值为true。
现在来完成保存按钮和重置按钮的操作。先完成重置按钮的,这个简单,调用表单的reset方法就行了,代码如下:
onReset: function () {
var me =this;
me.form.getForm().reset();
},
最后完成保存按钮,主要就是做表单提交,这个问题不大,直接调用表单的submit提交就行了,提交地址会在窗口显示前进行设置。现在要考虑的是提交成功后,怎么处理树的更新?新增的话比较简单,先检查它的父节点是否已经显示,如果还没有,就直接通过fullpath找到最顶层的根节点,然后展开它的全部子节点。如果已经存在,且已经展开,则调用appendChild方法追加就行了;如果存在,但没展开,则展开该节点就行了。
编辑操作比较复杂,很难处理,除非模仿树的拖放操作做相应的处理,这里就不做研究了,直接刷新Store。或者一种替代方式是编辑时禁止修改父类,只允许通过拖放方式改变父类,这里也不再做研究了,有兴趣自己做一下。
现在,先把提交过程写出来,再考虑刷新问题,代码如下:
onSave: function () {
var me = this,
f= me.form.getForm();
if(f.isValid()) {
f.submit({
//waitMsg:"正在保存,请等待……"
补充:Web开发 , 其他 ,