1 系统设计
简介
能够在线展示及编写html、js、css、php代码,拥有实时预览、代码高亮、自动完成、在线发布等多项特性,提供新建项目、文件上传、删除、下载及管理功能。
网址:https://ccgis.cn/jsEditor/modules/logreg/login/login.html
功能设计
系统分为以下三个功能模块,分别是项目管理模块、代码编辑及运行模块、工具栏,如下图所示。
2 关键技术
2.1 目录树的生成
根据用户的登录信息得到属于该用户的项目名称及项目文件所在路径,然后根据geoserver提供的fileserver接口,使用getdir方法得到每一个项目所拥有的文件路径。
若当前用户没有项目,就为其创建一个默认的项目,包含基本的文件结构:index.html文件、css文件夹、js文件夹、imgs文件夹和libs文件夹。
如果项目的数量特别大,需要多次的循环,为了防止长时间运行脚本,造成运行阻塞,用户无法与页面进行交互,需要对其使用数组分块技术,基本的思路是:使用定时器处理数组的一小部分,接着再设置另一个定时器,调用arguments.callee处理小一小块。
1 | setTimeout(function(){ |
将文件路径转换为节点的格式,每个节点包含id、pId、name、isParent等信息。1
var zNode = { id:zNodeId, pId:parentId, name:dirArr[i],isParent :isParent, open:openFlag, owner:dirArr[0] };
最后将得到的节点信息绑定到所在的ztree元素的id上,并为其设定相应的点击事件、双击事件及右键点击事件。1
$.fn.zTree.init($("#"+id), setting, zNodes);
2.2 编辑窗口与目录树关联
点击目录树到编辑窗口打开文件,使用了自定义事件绑定方法。
1 |
|
这种观察者的设计模式,由观察者及主体构成。观察者能够订阅事件即注册回调事件,在主文件中注册打开文件的事件处理程序,openFile函数执行的就是在编辑窗口请求并打开指定的文件:1
cataMod.addCustomEvt('open',openFile);
主体触发事件,在目录树的点击事件中,触发打开文件的事件。
catalog.trigger('open',args);
打开指定文件使用的是geoserver服务器提供的fileserver接口,使用getfile方法得到当前路径的文件内容。请求文件时在请求的URL中加上时间戳参数,保证每次请求的文件都是从服务器上获取的最新文件,而不是从浏览器的缓存中读取的。最后在标签栏里添加文件名标签,并用CodeMirror提供的setValue()方法填充代码窗口。
2.3 项目管理
2.3.1 新建项目
为项目添加默认目录结构,创建默认html文件,并包含基础的html结构,保存为字符串,使用encodeURIComponent()方法将字符串进行编码,作为URI的con参数,新建文件使用geoserver服务器fileserver接口的putstring方法。
创建默认的文件夹,使用fileserver接口mkdir方法新建css文件夹、js文件夹、imgs文件夹和libs文件夹。
最后利用WebsqlScript接口为用户在数据库中添加一条记录。
2.3.2 新建文件
新建文件后需要在目录树中增加一个新的节点,使用zTree.addNodes(pNode,zNode)添加节点,zTree.expandNode(zNode)将节点展开,并用zTree.selectNode(thisZNode)将该节点设为选中状态。
在编辑窗口添加一个新的文件标签,并将不同类型文件的默认内容更新到<textarea>
标签中。若新建的文件类型为js或css,则在对应的网页文档的<head>
标签中插入<script>
标签或<link>
标签。
2.3.3 删除文件
使用fileserver接口delete方法删除文件;利用ztree的removeNode()方法移除节点;然后判断当前文件是否在代码编辑窗口中打开,若打开则判断编辑窗口中可见的文件是否为要删除的文件,否的话直接删除文件的标签页和在对象中存储的信息,是的话则先判断当前标签页是否有下一个nodeType为1的同级节点元素并作为下一个要打开的文件,否则判断当前标签页是否有上一个nodeType为1的同级节点元素并作为下一个要打开的文件。
2.3.4 下载文件
首先将要下载的文件或文件夹通过fileserver接口dozip方法另存为一个zip格式的压缩文件;创建一个不可见的<iframe>
标签,将<iframe>
标签的src指向另存文件的路径;最后将标签加到文档中document.body.appendChild(elemIF)。
2.4 压缩文件上传
为更好地满足用户的需要,我们利用 HTML5 提供的 File API 实现上传文件的功能。Javascript 通过 File API 提供的 File、FileList、Blob 接口便可以读取本地文件。在 html5 中, File 对象支持选择多个文件, 用户选择了某些文件之后,便会触发 file 类型的 input 元素的 onchange 事件句柄。File 对象中包含了文件 的所有可访问信息,而不仅仅是文件名。
File API 还提供了一个异步读取文件的接口——FileReader,利用该接口我们可以异步地将文件内容 加载到内存中,赋予某个 js 变量。FileReader 包含了一套完整的事件模型,用于捕获读取文件时的状态 如 onabort (中断)、onerror (出错)、onloadstart (开始)、onprogress (正在读取)、onload (成功读取)等。 基于 FileReader,我们编写了用于多文件上传的 js 类库 gUpload.js,实现本地文件的读取、变量的处理、文件上传至服务器。
上传文件后在目录树中添加新的节点 ;若在根目录下上传则在数据库中添加一条记录;若上传的文件为压缩文件,geoserver会自动将文件解压到同级目录下,因此还需则将同级目录下的同名文件转换为节点添加到目录树中。
2.5 运行结果实时显示
代码编辑窗口使用了<textarea>
标签,在使用CodeMirror.fromTextArea()方法初始化编辑器对象时传入该标签元素,并设置相应的参数。运行结果的显示使用的是<iframe>
标签。
在代码编辑窗口编写完代码后,利用CodeMirror提供的getValue方法得到当前文件的内容,并保存到服务器中。再使用getMode方法判断当前文件类型,若非网页文档则找到当前文件对应的html文件的路径。最后将iframe的src属性指向html文件所在路径并加上随机数作为参数,就可以实现运行结果实时显示在页面中的效果。
3 存在的不足
3.1 编辑同一个文件存在冲突
当进行协同开发时,多个用户可能同时编辑同一个文件,这时候就极有可能出现冲突,若某个用户修改了文档中的某一部分并对其进行保存,而这时候另一个用户修改了文档中的另一部分并保存,这时候前一个用户修改的内容就会被后一个用户所覆盖。因此之后要考虑在后台将提交的字符串与后台文件合并的功能。
3.2 没有错误提示
目前查看错误只能通过打开浏览器的控制台的方式,这样不便于开发,接下来可以考虑将错误提示直接显示在系统中,更加方便用户进行开发。
附:
1)工具介绍
- 新建项目:输入项目名后,自动新建一个默认目录结构的项目。
- 新建js:选择所在项目,输入文件名,即新建js文件。
- 新建css:选择所在项目,输入文件名,即新建css文件。
- 第三方库:点击选择需要引入的库,即自动在当前打开的html文件的head标签中插入第三方库的路径,再次点击可取消引入。
- 保存:修改文件后,标签的图标会变为红点,点击保存后,文件保存到服务器,图标变为红色关闭按钮。
- 运行:点击“运行”按钮后,可在右边看到运行后的结果。
- 发布:点击“发布”按钮后,浏览器再打开一个标签页显示运行结果。
- 帮助:点击“帮助”按钮后,查询帮助文档。
- 类库文档:跳转到ccgis类库的说明文档。
- 注销:在界面右上角显示用户名和注销按钮,点击注销按钮后,页面跳转到登录界面。
2)快捷键说明
- Ctrl+Q:自动补全
- Ctrl+F:查找全部匹配的结果
- Alt+F:逐个跳到匹配的结果,
- enter:跳到下一个匹配结果,
- shift+enter:找到上一个匹配的结果
- Ctrl+H:替换
- Ctrl+L:选中一行,可以删除
- Ctrl+/: 注释掉选中的区域
- Ctrl+D: 同时选中多个匹配结果
- Shift-Ctrl-[:折叠
- Shift-Ctrl-]:展开折叠区域