2.1.2 广阔的天地——调用代码命令和调用URL命令
除了使用常用的内置命令外,MapGuide还为我们提供了两个强大的命令:调用代码命令和调用URL命令,这两种命令打破了内置命令的束缚,为MapGuide提供几乎无限多的扩展方式。
那么,究竟这两种命令是什么含义呢?
调用代码命令,故名思义,可以允许用户在地图页面中执行一小段Javascript脚本。MapGuide除了为我们提供大量的内置命令外,还为我们提供了很多可以用于Javascript脚本调用的函数,称为阅读器API(Viewer API)。这些API为我们提供了对于页面中不同部分的访问和控制,比如我们可以获得图例中各个层的情况,也可以在工具栏的命令执行结束后执行一段我们的程序。
如果地图页面中提供的阅读器API依然无法满足您的要求,那么您可能就会需要调用URL命令。调用URL命令允许您在指定的目标页面内加载您自行编写的页面,这样您就可以使用一些能够在服务器端动态生成页面的技术(如ASP.net、PHP或者JSP),通过网页API(Web API)来对地图进行更深层次的修改,比如动态添加一个临时层、或者修改图层的过滤条件等等。
由于现在的浏览器都支持动态访问与修改页面中的内容,这就使得如果能够把调用代码命令和调用URL命令结合起来,理论上讲就可以更改页面中的所有内容。这也就是前文中为什么说这两个命令提供的扩展方式是无限多的了。
也许,您已经开始跃跃欲试,准备写一个自己的命令了。别忙,还有一件事情您需要知道。而这件事情,大大关系着您编写脚本的思路。
2.2 搭积木的艺术——框架的嵌套
说出来可能会令您吃惊,MapGuide的基本网页布局虽然表面上如此整齐统一,其实却是由好多页面“拼凑“出来的(相比之下,灵活网页布局页面虽然元素很多,却除了任务窗格外,其余部分都是一个页面)。这就是为什么您虽然可以拖拽缩放滑块元素把它放置在地图上的任何部位,甚至图例窗格或属性窗格中,却永远无法把它放置在任务窗格中:因为他们属于不同的页面。
那么,众多页面时怎么“拼凑”成一个整体的呢?这其实是借助了浏览器客户端HTML中的一个技术,叫做框架(frame)与框架集(frameset)。这个技术允许我们将一个浏览器的页面分割成几个部分,每个部分加载不同的网页。如果您对这个技术还不是很清楚,可以查阅HTML相关部分的文档。
不仅MapGuide的基本网页布局是由很多个页面组成,而且有些页面内部还嵌套着其他页面,从而形成了一个含有层次结构的框架嵌套体系。
图2-3显示的是含有任务栏时基本网页布局中各个框架是如何嵌套的。
图2-3 基本网页布局中含有任务栏时各个框架的嵌套关系
首先,MapGuide的主框架页面,也就是基本网页布局的框架嵌套体系中最大的一个框架,它的地址是“/mapguide/mapviewerajax/?SESSION=sessionId&WEBLAYOUT=weblayout”,MapGuide支持用户使用一个框架集来同时放置这个页面和一个用户自己的横幅,但这完全是可选的,用户完全可以只使用MapGuide主框架页面作为页面本身而不添加自己的页面。用户甚至按照自己的需求来在页面中放置一个指向MapGuide主框架页面的框架来将整个基本网页布局嵌入到自己的网页中。
MapGuide主框架由上下两部分组成,下面的框架在代码中表示为sbFrame,里面放置的是状态栏,当布局中不包含状态栏时,下面的框架高度为0。
而位于主框架上面的子框架集,在代码中表示为mainAppFrame。又是由左右两个框架集组成,左面的的部分叫做mapArea,包含的是跟地图有关的内容,右面的部分叫做taskArea,包含的是跟任务相关的内容。
左边的mapArea由四个框架纵向排列而成,按照从上到下的顺序依次为:
1. tbFrame,里面放置的是工具栏
2. mapFrame,里面放置的是地图部分(包括图例和属性窗格)
3. formFrame,这个框架是隐藏的(高度为0),用来通过HTTP POST发送数据到服务器端
4. scriptFrame,这个框架也是隐藏的(高度为0),用于加载和执行对用户看不见的页面。通常我们用这个框架来执行客户端的Javascript脚本。
右边的taskArea由上下两部分构成:上面的是taskBar,里面放置的是任务栏;下面的是叫taskFrame,又是由放置任务列表的taskListFrame和放置任务窗格的taskPaneFrame两部分组成的。taskFrame是一个包括含框架集的独立的页面,而不是主框架集的一个子框架集。神奇的是,虽然功能上taskBar和taskListFrame更紧密,当我们点击任务栏上的任务下拉时就能展开任务列表,而实际上从页面组成上说,taskListFrame却跟taskPaneFrame更为相关(这一点也正印证了程序结构设计和程序功能设计在有些情况下并不是一个思路)。
当我们选择在基本网页布局中不放置任务栏的时候,框架结构与放置任务栏的时候不太一样。主框架由上中下三部分组成,上面是放置工具栏的tbFrame,下面是放置状态栏的sbFrame,而中间是跟地图和任务相关的mapArea。mapArea是由四个框架横向排列而成,从左至右依次为放置地图部分的mapFrame,放置任务列表(在不放置任务栏的时候永远隐藏)和任务窗格的taskFrame,隐藏的formFrame和scriptFrame。
由于历史原因,基本网页布局采用的是较为陈旧的框架/框架集结构。以今天的眼光看来,这一结构存在着很多缺陷,为此基本网页布局走了不少弯路,来弥补这些不足。举个例子来说,一个框架内页面上的组件是不能跨越框架边界显示在另一个框架内的页面中的,这就使得工具栏页面中的下拉列表不能采用普通的下拉控件。否则,因为下拉内容是在工具栏的页面中的,超过工具栏页面的部分会被截断而显示不出来。为此,mapFrame中写了很多代码,使得在点击工具栏的下拉按钮时,能够在mapFrame中与工具栏下拉按钮对齐的位置上显示出一个含有下拉内容的小块(div)。在后面的章节,我们可以看到,由于使用了新的技术,灵活网页布局并没有出现这样的问题。
对于开发人员而言,了解这个网页嵌套关系非常重要。如果您在开发一个在任务窗格中加载的页面时,想在页面中用Javascript访问主框架调用主框架中的一个API,根据网页嵌套关系,您就可以知道,您可以通过parent.parent来访问主框架的window对象。如果您的代码是执行在scriptFrame中的,那么您就需要用parent来访问主框架的window对象。
另外一个很重要的地方就是,主框架提供了一些API来让我们访问各个子框架。比如GetFormFrame,GetMapFrame,GetScriptFrame,GetTaskFrame。其实,知道了这些子框架与子框架集的名字,我们也可以通过主框架所在页面的这些变量,如formFrame等,来访问各个框架的window对象。
[To be continued by 2.3 开始动手吧——Hello Viewer]