diff --git a/config/config.php b/config/config.php
index 038e3973ff..3bfd29f7aa 100644
--- a/config/config.php
+++ b/config/config.php
@@ -119,4 +119,4 @@ define('TABLE_ACTION', '`' . $config->db->prefix . 'action`');
define('TABLE_FILE', '`' . $config->db->prefix . 'file`');
define('TABLE_HISTORY', '`' . $config->db->prefix . 'history`');
define('TABLE_EXTENSION', '`' . $config->db->prefix . 'extension`');
-define('TABLE_WEBAPP', '`' . $config->db->prefix . 'webApp`');
+define('TABLE_WEBAPP', '`' . $config->db->prefix . 'webapp`');
diff --git a/db/update3.3.sql b/db/update3.3.sql
index 05a562f7dc..341705dca4 100644
--- a/db/update3.3.sql
+++ b/db/update3.3.sql
@@ -7,18 +7,20 @@ ALTER TABLE `zt_case` CHANGE `pri` `pri` TINYINT( 3 ) UNSIGNED NOT NULL ;
ALTER TABLE `zt_action` ADD `read` ENUM( '0', '1' ) NOT NULL DEFAULT '0';
UPDATE `zt_action` SET `read` = '1';
-CREATE TABLE IF NOT EXISTS `zt_webApp` (
+CREATE TABLE IF NOT EXISTS `zt_webapp` (
`id` mediumint(9) NOT NULL auto_increment,
`appid` mediumint(9) NOT NULL,
- `name` varchar(100) NOT NULL,
- `account` char(30) NOT NULL,
`module` mediumint(9) NOT NULL,
+ `name` varchar(100) NOT NULL,
+ `author` varchar(30) NOT NULL,
`url` varchar(100) NOT NULL,
- `icon` mediumint(9) NOT NULL,
+ `icon` varchar(100) NOT NULL,
`target` varchar(50) NOT NULL,
`size` varchar(20) NOT NULL,
- `author` varchar(30) NOT NULL,
`desc` text NOT NULL,
+ `addedBy` char(30) NOT NULL,
`addedDate` datetime NOT NULL,
+ `addType` varchar(20) NOT NULL default 'system',
+ `views` mediumint(9) NOT NULL,
PRIMARY KEY (`id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
diff --git a/module/common/lang/en.php b/module/common/lang/en.php
index fa9010d3e5..1371b954d9 100644
--- a/module/common/lang/en.php
+++ b/module/common/lang/en.php
@@ -83,7 +83,7 @@ $lang->menu->project = 'Project|project|index';
$lang->menu->qa = 'Test|qa|index';
$lang->menu->doc = 'Doc|doc|index';
$lang->menu->report = 'Report|report|index';
-$lang->menu->resource = 'Resource|resource|index';
+$lang->menu->webapp = 'Web App|webapp|index';
$lang->menu->company = 'Company|company|index';
$lang->menu->admin = 'Admin|admin|index';
@@ -204,8 +204,8 @@ $lang->report->menu->test = array('link' => 'Test|report|bugsummary', 'alias'
$lang->report->menu->staff = array('link' => 'Company|report|workload');
/* Resource menu. */
-$lang->resource->menu->addedApp = array('link' => 'Added App|resource|index');
-$lang->resource->menu->obtain = array('link' => 'Obtain App|resource|obtain');
+$lang->webapp->menu->addedApp = array('link' => 'Added App|webapp|index');
+$lang->webapp->menu->obtain = array('link' => 'Obtain App|webapp|obtain');
/* Company menu. */
$lang->company->menu->name = '%s' . $lang->arrow;
diff --git a/module/common/lang/menuOrder.php b/module/common/lang/menuOrder.php
index e999525536..008585e05c 100644
--- a/module/common/lang/menuOrder.php
+++ b/module/common/lang/menuOrder.php
@@ -6,7 +6,7 @@ $lang->menuOrder[15] = 'project';
$lang->menuOrder[20] = 'qa';
$lang->menuOrder[25] = 'doc';
$lang->menuOrder[30] = 'report';
-$lang->menuOrder[35] = 'resource';
+$lang->menuOrder[35] = 'webapp';
$lang->menuOrder[40] = 'company';
$lang->menuOrder[45] = 'admin';
diff --git a/module/common/lang/zh-cn.php b/module/common/lang/zh-cn.php
index 38dbcf2a09..63409842e1 100644
--- a/module/common/lang/zh-cn.php
+++ b/module/common/lang/zh-cn.php
@@ -83,7 +83,7 @@ $lang->menu->project = '项目视图|project|index';
$lang->menu->qa = '测试视图|qa|index';
$lang->menu->doc = '文档视图|doc|index';
$lang->menu->report = '统计视图|report|index';
-$lang->menu->resource = '资源视图|resource|index';
+$lang->menu->webapp = '应用中心|webapp|index';
$lang->menu->company = '组织视图|company|index';
$lang->menu->admin = '后台管理|admin|index';
@@ -204,8 +204,7 @@ $lang->report->menu->test = array('link' => '测试|report|bugsummary', 'alia
$lang->report->menu->staff = array('link' => '组织|report|workload');
/* 资源视图菜单设置。*/
-$lang->resource->menu->addedApp = array('link' => '已有应用|resource|index');
-$lang->resource->menu->obtain = array('link' => '获得应用|resource|obtain');
+$lang->webapp->menu->obtain = array('link' => '应用商店|webapp|obtain', 'float' => 'right');
/* 组织结构视图菜单设置。*/
$lang->company->menu->name = '%s' . $lang->arrow;
diff --git a/module/common/model.php b/module/common/model.php
index b5b31f444a..93e3038c86 100644
--- a/module/common/model.php
+++ b/module/common/model.php
@@ -134,6 +134,7 @@ class commonModel extends model
if($module == 'misc' and $method == 'about') return true;
if($module == 'misc' and $method == 'checkupdate') return true;
if($module == 'help' and $method == 'field') return true;
+ if($module == 'webapp' and $method == 'ajaxaddview') return true;
return false;
}
diff --git a/module/group/lang/resource.php b/module/group/lang/resource.php
index f97b6e2cb2..edb77388a0 100644
--- a/module/group/lang/resource.php
+++ b/module/group/lang/resource.php
@@ -636,6 +636,20 @@ $lang->convert->methodOrder[45] = 'execute';
$lang->convert->methodOrder[50] = 'convertBugFree';
$lang->convert->methodOrder[55] = 'convertRedmine';
+$lang->resource->webapp->index = 'index';
+$lang->resource->webapp->obtain = 'obtain';
+$lang->resource->webapp->create = 'create';
+$lang->resource->webapp->edit = 'edit';
+$lang->resource->webapp->install = 'install';
+$lang->resource->webapp->uninstall = 'uninstall';
+
+$lang->webapp->methodOrder[5] = 'index';
+$lang->webapp->methodOrder[10] = 'obtain';
+$lang->webapp->methodOrder[15] = 'create';
+$lang->webapp->methodOrder[20] = 'edit';
+$lang->webapp->methodOrder[25] = 'install';
+$lang->webapp->methodOrder[30] = 'uninstall';
+
/* Others. */
$lang->resource->api->getModel = 'getModel';
diff --git a/module/index/lang/zh-cn.php b/module/index/lang/zh-cn.php
index 9a87968dcc..ce06e0c7ff 100644
--- a/module/index/lang/zh-cn.php
+++ b/module/index/lang/zh-cn.php
@@ -2,9 +2,9 @@
$lang->index->common = '首页';
$lang->index->index = '首页';
-$lang->index->selectSoftType = '请选择禅道使用方式';
+$lang->index->selectFlow = '请选择禅道使用方式';
-$lang->index->softType['all'] = '全生命周期管理(禅道完全功能)';
-$lang->index->softType['zentaotest'] = '测试管理(禅道测试管理扩展,去掉了需求、任务管理,只保留bug管理、用例管理和测试任务管理,可以只用作测试跟踪)';
-$lang->index->softType['zentaotask'] = '任务管理(禅道任务管理扩展,去掉了需求、测试管理,只保留任务管理,可以只用作简单任务跟踪)';
-$lang->index->softType['zentaostory'] = '需求管理(禅道需求管理扩展,去掉了任务、测试管理,只保留需求管理,可以只用作需求整理)';
+$lang->index->flowList['full'] = '全生命周期管理(禅道完全功能)';
+$lang->index->flowList['onlyTest'] = '测试管理(禅道测试管理扩展,去掉了需求、任务管理,只保留bug管理、用例管理和测试任务管理,可以只用作测试跟踪)';
+$lang->index->flowList['onlyTask'] = '任务管理(禅道任务管理扩展,去掉了需求、测试管理,只保留任务管理,可以只用作简单任务跟踪)';
+$lang->index->flowList['onlyStory'] = '需求管理(禅道需求管理扩展,去掉了任务、测试管理,只保留需求管理,可以只用作需求整理)';
diff --git a/module/task/js/create.js b/module/task/js/create.js
index 3e788a760f..c9454f2294 100644
--- a/module/task/js/create.js
+++ b/module/task/js/create.js
@@ -32,7 +32,9 @@ function setPreview()
}
else
{
- storyLink = createLink('story', 'view', "storyID=" + $('#story').val());
+ storyLink = createLink('story', 'view', "storyID=" + $('#story').val());
+ var concat = config.requestType == 'PATH_INFO' ? '?' : '&';
+ storyLink = storyLink + concat + 'onlybody=yes';
$('#preview').removeClass('hidden');
$('#preview').attr('href', storyLink);
}
diff --git a/module/tree/control.php b/module/tree/control.php
index a8b34f0637..225b70de63 100644
--- a/module/tree/control.php
+++ b/module/tree/control.php
@@ -127,6 +127,19 @@ class tree extends control
$position[] = html::a($this->createLink('doc', 'browse', "libID=$rootID"), $lib->name);
$position[] = $this->lang->tree->manageCustomDoc;
}
+ elseif(strpos($viewType, 'webapp') !== false)
+ {
+ $this->loadModel('webapp')->setMenu();
+ $this->lang->tree->menu = $this->lang->webapp->menu;
+ $this->lang->set('menugroup.tree', 'webapp');
+
+ $header['title'] = $this->lang->tree->manageWebapp;
+ $position[] = $this->lang->tree->manageWebapp;
+
+ $root->name = $this->lang->tree->manageWebapp;
+ $root->id = 0;
+ $this->view->root = $root;
+ }
$parentModules = $this->tree->getParents($currentModuleID);
$this->view->header = $header;
diff --git a/module/tree/js/browse.js b/module/tree/js/browse.js
index 18abf383e9..afd649ea72 100644
--- a/module/tree/js/browse.js
+++ b/module/tree/js/browse.js
@@ -1,4 +1,4 @@
-function syncModule(rootID, type = 'story')
+function syncModule(rootID, type)
{
if(type == 'story') moduleID = $('#productModule').val();
if(type == 'task') moduleID = $('#projectModule').val();
@@ -22,7 +22,7 @@ function syncModule(rootID, type = 'story')
})
}
-function syncProductOrProject(obj, type = 'product')
+function syncProductOrProject(obj, type)
{
if(type == 'product') viewType = 'story';
if(type == 'project') viewType = 'task';
diff --git a/module/tree/lang/zh-cn.php b/module/tree/lang/zh-cn.php
index 514c0f2e51..e95ed4051b 100644
--- a/module/tree/lang/zh-cn.php
+++ b/module/tree/lang/zh-cn.php
@@ -21,6 +21,7 @@ $lang->tree->manageProduct = '维护产品视图模块';
$lang->tree->manageProject = '维护项目视图模块';
$lang->tree->manageBug = '维护测试视图模块';
$lang->tree->manageCase = '维护用例视图模块';
+$lang->tree->manageWebapp = '维护WEB应用分类';
$lang->tree->manageCustomDoc = '维护文档库分类';
$lang->tree->updateOrder = '更新排序';
$lang->tree->manageChild = '维护子模块';
diff --git a/module/tree/model.php b/module/tree/model.php
index fad2dd20d6..0f5ff0bd9c 100644
--- a/module/tree/model.php
+++ b/module/tree/model.php
@@ -357,6 +357,20 @@ class treeModel extends model
return $linkHtml;
}
+ /**
+ * Create Webapp Link
+ *
+ * @param int $module
+ * @param int $extra
+ * @access public
+ * @return void
+ */
+ public function createWebappLink($module, $extra)
+ {
+ $linkHtml = html::a(helper::createLink('webapp', 'index', "module={$module->id}"), $module->name, '_self', "id='module{$module->id}'");
+ return $linkHtml;
+ }
+
/**
* Get sons of a module.
*
diff --git a/module/tree/view/browse.html.php b/module/tree/view/browse.html.php
index e84dccfe38..d3defca641 100644
--- a/module/tree/view/browse.html.php
+++ b/module/tree/view/browse.html.php
@@ -60,7 +60,7 @@
}
echo '
';
}
- elseif($viewType != 'story' and strpos($viewType, 'doc') === false)
+ elseif($viewType != 'story' and strpos($viewType, 'doc') === false and $viewType != 'webapp')
{
echo html::select('productModule', $productModules, '', 'class=select-3');
echo html::commonButton($lang->tree->syncFromProduct, 'onclick=syncModule('.$rootID.')');
diff --git a/module/webapp/config.php b/module/webapp/config.php
new file mode 100644
index 0000000000..df36ea57a9
--- /dev/null
+++ b/module/webapp/config.php
@@ -0,0 +1,5 @@
+webapp->url = 'http://www.zentao.com';
+$config->webapp->apiRoot = $config->webapp->url . '/webapp-';
+
+$config->webapp->create->requiredFields = 'name,url,target';
diff --git a/module/webapp/control.php b/module/webapp/control.php
new file mode 100644
index 0000000000..91311b177f
--- /dev/null
+++ b/module/webapp/control.php
@@ -0,0 +1,171 @@
+
+ * @package webapp
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+class webapp extends control
+{
+ /**
+ * Index for webapp.
+ *
+ * @param int $module
+ * @access public
+ * @return void
+ */
+ public function index($module = 0)
+ {
+ $module = (int)$module;
+ $webapps = $this->webapp->getLocalApps('id', $module);
+
+ $this->webapp->setMenu($module);
+
+
+ $this->view->webapps = $webapps;
+ $this->view->moduleTree = $this->loadModel('tree')->getTreeMenu(0, 'webapp', 0, array('treeModel', 'createWebappLink'));
+ $this->view->module = $module;
+ $this->display();
+ }
+
+ /**
+ * Obtain web app.
+ *
+ * @param string $type
+ * @param string $param
+ * @param int $recTotal
+ * @param int $recPerPage
+ * @param int $pageID
+ * @access public
+ * @return void
+ */
+ public function obtain($type = 'byUpdatedTime', $param = '', $recTotal = 0, $recPerPage = 10, $pageID = 1)
+ {
+ $this->webapp->setMenu();
+ /* Init vars. */
+ $type = strtolower($type);
+ $moduleID = $type == 'bymodule' ? (int)$param : 0;
+ $webapps = array();
+ $pager = null;
+
+ /* Set the key. */
+ if($type == 'bysearch') $param = helper::safe64Encode($this->post->key);
+
+ /* Get results from the api. */
+ $results = $this->webapp->getAppsByAPI($type, $param, $recTotal, $recPerPage, $pageID);
+ if($results)
+ {
+ $this->app->loadClass('pager', $static = true);
+ $pager = new pager($results->dbPager->recTotal, $results->dbPager->recPerPage, $results->dbPager->pageID);
+ $webapps = $results->webapps;
+ }
+
+ $this->view->moduleTree = $this->webapp->getModulesByAPI();
+ $this->view->webapps = $webapps;
+ $this->view->installeds = $this->webapp->getLocalApps('appid');
+ $this->view->pager = $pager;
+ $this->view->tab = 'obtain';
+ $this->view->type = $type;
+ $this->view->moduleID = $moduleID;
+ $this->display();
+ }
+
+ /**
+ * Edit web app.
+ *
+ * @param int $webappID
+ * @access public
+ * @return void
+ */
+ public function edit($webappID)
+ {
+ if($_POST)
+ {
+ $this->webapp->update($webappID);
+ if(dao::isError())die(js::error(dao::getError()));
+ die(js::reload('parent.parent'));
+ }
+
+ $this->view->modules = $this->webapp->getModules();
+ $this->view->webapp = $this->webapp->getLocalAppByID($webappID);
+ $this->display();
+ }
+
+ /**
+ * Create web app.
+ *
+ * @access public
+ * @return void
+ */
+ public function create()
+ {
+ if($_POST)
+ {
+ $webappID = $this->webapp->create();
+ if(dao::isError())die(js::error(dao::getError()));
+ die(js::locate(inlink('index'), 'parent'));
+ }
+
+ $this->webapp->setMenu();
+
+ $this->view->modules = $this->webapp->getModules();
+ $this->display();
+ }
+
+ /**
+ * Install web app.
+ *
+ * @param int $webappID
+ * @access public
+ * @return void
+ */
+ public function install($webappID)
+ {
+ if($_POST)
+ {
+ $result = $this->webapp->install($webappID);
+ if(dao::isError())
+ {
+ echo js::error(dao::getError());
+ die(js::reload('parent'));
+ }
+ echo js::alert($this->lang->webapp->successInstall);
+ die(js::locate(inlink('index'), 'parent.parent'));
+ }
+
+ $this->view->modules = $this->webapp->getModules();
+ $this->display();
+ }
+
+ /**
+ * uninstall web app.
+ *
+ * @param int $webappID
+ * @param string $confirm
+ * @access public
+ * @return void
+ */
+ public function uninstall($webappID, $confirm = 'no')
+ {
+ if($confirm == 'no') die(js::confirm($this->lang->webapp->confirmDelete, inlink('uninstall', "webappID=$webappID&confirm=yes")));
+
+ $this->dao->delete()->from(TABLE_WEBAPP)->where('id')->eq($webappID)->exec(false);
+ die(js::reload('parent'));
+ }
+
+ /**
+ * Views add one by ajax.
+ *
+ * @param int $webappID
+ * @access public
+ * @return void
+ */
+ public function ajaxAddView($webappID)
+ {
+ $this->dao->update(TABLE_WEBAPP)->set('views=views+1')->where('id')->eq($webappID)->exec(false);
+ }
+}
diff --git a/module/webapp/css/common.css b/module/webapp/css/common.css
new file mode 100644
index 0000000000..88ebfd5b1c
--- /dev/null
+++ b/module/webapp/css/common.css
@@ -0,0 +1,11 @@
+.active a {color:blue; font-weight:bold;}
+.button-c {padding:1px 3px; border:1px solid gray; background:#e4e4ef; color:black; text-decoration:none}
+.error {color:red; font-size:14px}
+.success {color:green; font-size:14px}
+
+.exttable td {padding:10px 5px 5px 10px}
+.exttable caption{background:#efefef; border-color:#CCC9C9; margin-left:0}
+.exttable {border-color:#CCC9C9; border-top:none;}
+.exttable td{border-color:#CCC9C9}
+
+small{font-weight:normal}
diff --git a/module/webapp/js/common.js b/module/webapp/js/common.js
new file mode 100644
index 0000000000..89e97fa0ab
--- /dev/null
+++ b/module/webapp/js/common.js
@@ -0,0 +1,46 @@
+if($('a.iframe').size()) $("a.iframe").colorbox({width:450, height:220, iframe:true, transition:'elastic', speed:350, scrolling:true});
+if($('a.webapp').size()) $("a.webapp").colorbox({width:600, height:400, iframe:true, transition:'elastic', speed:350, scrolling:true});
+if($('a.popup').size()) $("a.popup").colorbox({width:200, height:100, iframe:true, transition:'elastic', speed:350, scrolling:true});
+
+function popup(width, height)
+{
+ $("a.popup").colorbox({width:width, height:height});
+}
+
+var show = false;
+var url = '';
+function toggleShowapp(webappID)
+{
+ height = document.body.clientHeight - 60;
+ if(!show)
+ {
+ if(url == '') url = $('#useapp' + webappID).attr('href');
+ $('#useapp' + webappID).attr('href', '#iframe' + webappID);
+ var html = "
|
";
+ $('#webapp' + webappID).append(html);
+ show = true;
+ }
+ else
+ {
+ $('#iframe' + webappID).remove();
+ show = false;
+ }
+}
+
+function setSize(target)
+{
+ $('.size').hide();
+ if(target == 'popup') $('.size').show();
+}
+
+function addView(webappID)
+{
+ $.get(createLink('webapp', 'ajaxAddView', 'webappID=' + webappID));
+}
+
+$(function(){
+ setSize($('#target').val());
+ $('#target').change(function(){setSize($(this).val())});
+ $('#modulemenu ul li').removeClass('active');
+ if(typeof(module) != "undefined") $('#modulemenu ul li #submenu' + module).parent().addClass('active');
+})
diff --git a/module/webapp/lang/en.php b/module/webapp/lang/en.php
new file mode 100644
index 0000000000..1f6befc87e
--- /dev/null
+++ b/module/webapp/lang/en.php
@@ -0,0 +1,63 @@
+
+ * @package webapp
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+$lang->webapp->common = 'Web App';
+$lang->webapp->index = 'Added App';
+$lang->webapp->obtain = 'Obtain App';
+
+$lang->webapp->install = 'Install App';
+$lang->webapp->useapp = 'Use App';
+$lang->webapp->installed = 'Installed';
+$lang->webapp->edit = 'Edit App';
+$lang->webapp->customAdd = 'Custom Add';
+
+$lang->webapp->id = 'ID';
+$lang->webapp->name = 'Name';
+$lang->webapp->url = 'Link Address';
+$lang->webapp->icon = 'Icon';
+$lang->webapp->module = 'App Category';
+$lang->webapp->author = 'Author';
+$lang->webapp->desc = 'Desc';
+$lang->webapp->target = 'Target';
+$lang->webapp->size = 'Size';
+$lang->webapp->height = 'Height';
+$lang->webapp->addedTime = 'Add Time';
+$lang->webapp->updatedTime = 'Update Time';
+$lang->webapp->downloads = 'Downloads';
+$lang->webapp->grade = 'Grade';
+$lang->webapp->addType = 'Add Type';
+$lang->webapp->packup = 'Pack Up';
+
+$lang->webapp->byDownloads = 'Most Downloads';
+$lang->webapp->byAddedTime = 'New Add';
+$lang->webapp->byUpdatedTime = 'New Update';
+$lang->webapp->bySearch = 'Search';
+$lang->webapp->byCategory = 'Category';
+
+$lang->webapp->selectModule = 'Select Category:';
+$lang->webapp->allModule = 'All';
+$lang->webapp->noModule = 'Uncategorized';
+
+$lang->webapp->targetList['popup'] = 'Poput';
+$lang->webapp->targetList['inline'] = 'Inline';
+$lang->webapp->targetList['blank'] = 'New Window';
+
+$lang->webapp->sizeList['900x600'] = "900 x 600";
+$lang->webapp->sizeList['700x600'] = "700 x 600";
+$lang->webapp->sizeList['600x500'] = "600 x 500";
+
+$lang->webapp->addTypeList['system'] = 'System App';
+$lang->webapp->addTypeList['custom'] = 'Custom App';
+
+$lang->webapp->errorGetModules = "Get extensions' categories data from the www.zentao.net failed. ";
+$lang->webapp->errorGetExtensions = 'Get extensions from www.zentao.net failed. You can visit www.zentao.net to find your extensions, download it manually and then upload to zentaopms to install it.';
+$lang->webapp->successInstall = 'Success Install App.';
+$lang->webapp->confirmDelete = 'Are you sure delete this app?';
diff --git a/module/webapp/lang/zh-cn.php b/module/webapp/lang/zh-cn.php
new file mode 100644
index 0000000000..2c3e7c7304
--- /dev/null
+++ b/module/webapp/lang/zh-cn.php
@@ -0,0 +1,65 @@
+
+ * @package webapp
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+$lang->webapp->common = 'WEB应用';
+$lang->webapp->index = '已加应用';
+$lang->webapp->obtain = '获得应用';
+
+$lang->webapp->install = '安装应用';
+$lang->webapp->uninstall = '移除应用';
+$lang->webapp->useapp = '使用';
+$lang->webapp->installed = '已添加';
+$lang->webapp->edit = '编辑应用';
+$lang->webapp->create = '创建应用';
+$lang->webapp->manageTree = '维护分类';
+
+$lang->webapp->id = '编号';
+$lang->webapp->name = '名称';
+$lang->webapp->url = '链接地址';
+$lang->webapp->icon = '图标';
+$lang->webapp->module = 'WEB分类';
+$lang->webapp->author = '作者';
+$lang->webapp->desc = '简介';
+$lang->webapp->target = '打开方式';
+$lang->webapp->size = '大小';
+$lang->webapp->height = '高度';
+$lang->webapp->addedTime = '添加时间';
+$lang->webapp->updatedTime = '更新时间';
+$lang->webapp->downloads = '下载量';
+$lang->webapp->grade = '评分';
+$lang->webapp->addType = '添加类型';
+$lang->webapp->packup = '收起';
+
+$lang->webapp->byDownloads = '最多下载';
+$lang->webapp->byAddedTime = '最新添加';
+$lang->webapp->byUpdatedTime = '最近更新';
+$lang->webapp->bySearch = '搜索';
+$lang->webapp->byCategory = '分类浏览';
+
+$lang->webapp->selectModule = '选择分类:';
+$lang->webapp->allModule = '所有';
+$lang->webapp->noModule = '未分类';
+
+$lang->webapp->targetList['popup'] = '弹窗';
+$lang->webapp->targetList['inline'] = '内嵌';
+$lang->webapp->targetList['blank'] = '新窗口';
+
+$lang->webapp->sizeList['900x600'] = "900 x 600";
+$lang->webapp->sizeList['700x600'] = "700 x 600";
+$lang->webapp->sizeList['600x500'] = "600 x 500";
+
+$lang->webapp->addTypeList['system'] = '系统应用';
+$lang->webapp->addTypeList['custom'] = '自定义应用';
+
+$lang->webapp->errorGetModules = '从www.zentao.net获得插件分类失败。可能是因为网络方面的原因,请检查后重新刷新页面。';
+$lang->webapp->errorGetExtensions = '从www.zentao.net获得插件失败。可能是因为网络方面的原因,您可以到www.zentao.net手工下载插件,然后上传安装。';
+$lang->webapp->successInstall = '成功安装应用!';
+$lang->webapp->confirmDelete = '是否删除该应用?';
diff --git a/module/webapp/model.php b/module/webapp/model.php
new file mode 100644
index 0000000000..e2fbc80a8e
--- /dev/null
+++ b/module/webapp/model.php
@@ -0,0 +1,281 @@
+
+ * @package webapp
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+class webappModel extends model
+{
+
+ /**
+ * The api agent(use snoopy).
+ *
+ * @var object
+ * @access public
+ */
+ public $agent;
+
+ /**
+ * The api root.
+ *
+ * @var string
+ * @access public
+ */
+ public $apiRoot;
+
+ /**
+ * The construct function.
+ *
+ * @access public
+ * @return void
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAgent();
+ $this->setApiRoot();
+ $this->loadModel('tree');
+ }
+
+ /**
+ * Set menu.
+ *
+ * @param array $projects
+ * @param int $projectID
+ * @param string $extra
+ * @access public
+ * @return void
+ */
+ public function setMenu($module = null)
+ {
+ $modules = $this->getModules();
+
+ $moduleName = $this->app->getModuleName();
+ $methodName = $this->app->getMethodName();
+ foreach($modules as $moduleID => $module)
+ {
+ $module = trim($module, '/');
+ $this->lang->webapp->menu->$moduleID = array('link' => "$module|webapp|index|module=$moduleID");
+ }
+ $this->lang->webapp->menu->manageTree = array('link' => "{$this->lang->webapp->manageTree}|tree|browse|rootID=0&view=webapp", 'float' => 'right');
+ $this->lang->webapp->menu->create = array('link' => "{$this->lang->webapp->create}|webapp|create", 'float' => 'right');
+ }
+
+
+ /**
+ * Set the api agent.
+ *
+ * @access public
+ * @return void
+ */
+ public function setAgent()
+ {
+ $this->agent = $this->app->loadClass('snoopy');
+ }
+
+ /**
+ * Set the apiRoot.
+ *
+ * @access public
+ * @return void
+ */
+ public function setApiRoot()
+ {
+ $this->apiRoot = $this->config->webapp->apiRoot;
+ }
+
+ /**
+ * Fetch data from an api.
+ *
+ * @param string $url
+ * @access public
+ * @return mixed
+ */
+ public function fetchAPI($url)
+ {
+ $this->agent->fetch($url);
+ $result = json_decode($this->agent->results);
+
+ if(!isset($result->status)) return false;
+ if($result->status != 'success') return false;
+ if(isset($result->data) and md5($result->data) != $result->md5) return false;
+ if(isset($result->data)) return json_decode($result->data);
+ }
+
+ /**
+ * Get webapp modules from the api.
+ *
+ * @access public
+ * @return string|bool
+ */
+ public function getModulesByAPI()
+ {
+ $requestType = $this->config->requestType;
+ $webRoot = helper::safe64Encode($this->config->webRoot);
+ $apiURL = $this->apiRoot . 'apiGetmodules-' . $requestType . '-' . $webRoot . '.json';
+ $data = $this->fetchAPI($apiURL);
+ if(isset($data->modules)) return $data->modules;
+ return false;
+ }
+
+ /**
+ * Get webapps by some condition.
+ *
+ * @param string $type
+ * @param mixed $param
+ * @access public
+ * @return array|bool
+ */
+ public function getAppsByAPI($type, $param, $recTotal = 0, $recPerPage = 20, $pageID = 1)
+ {
+ $apiURL = $this->apiRoot . "apiGetApps-$type-$param-$recTotal-$recPerPage-$pageID.json";
+ $data = $this->fetchAPI($apiURL);
+ return $data;
+ }
+
+ /**
+ * Get a app info by API
+ *
+ * @param int $webappID
+ * @access public
+ * @return void
+ */
+ public function getAppInfoByAPI($webappID)
+ {
+ $apiURL = $this->apiRoot . "apiGetAppInfo-$webappID.json";
+ $data = $this->fetchAPI($apiURL);
+ return $data;
+ }
+
+ /**
+ * Get webapps by status.
+ *
+ * @param string $status
+ * @access public
+ * @return array
+ */
+ public function getLocalApps($key = 'id', $module = 0)
+ {
+ $webapps = $this->dao->select('*')->from(TABLE_WEBAPP)
+ ->beginIF($module != 0)->where('module')->eq($module)->fi()
+ ->fetchAll($key, false);
+ $localIcons = array();
+ foreach($webapps as $webapp)
+ {
+ if($webapp->addType == 'custom') $localIcons[$webapp->id] = $webapp->icon;
+ }
+
+ if($localIcons)
+ {
+ $files = $this->dao->select('*')->from(TABLE_FILE)->where('id')->in($localIcons)->fetchAll('id');
+ $fileWebPath = $this->loadModel('file')->webPath;
+ foreach($localIcons as $webappID => $icon)
+ {
+ if(isset($files[$icon])) $webapps[$webappID]->icon = $fileWebPath . $files[$icon]->pathname;
+ }
+ }
+
+ return $webapps;
+ }
+
+ /**
+ * Get webapp info from database.
+ *
+ * @param string $webapp
+ * @access public
+ * @return object
+ */
+ public function getLocalAppByID($webappID)
+ {
+ return $this->dao->select('*')->from(TABLE_WEBAPP)->where('id')->eq($webappID)->fetch('', false);
+ }
+
+ /**
+ * Install web app.
+ *
+ * @param int $webappID
+ * @access public
+ * @return void
+ */
+ public function install($webappID)
+ {
+ $data = $this->getAppInfoByAPI($webappID);
+ $webapp = $data->webapp;
+ $webapp->icon = $this->config->webapp->url . $webapp->icon->webPath;
+ $webapp->addedDate = helper::now();
+ $webapp->addedBy = $this->app->user->account;
+ $webapp->module = $this->post->module;
+ $webapp->appid = $webapp->id;
+ unset($webapp->account);
+ unset($webapp->status);
+ unset($webapp->url);
+ unset($webapp->id);
+ unset($webapp->grade);
+ unset($webapp->updatedDate);
+ unset($webapp->downloads);
+ $this->dao->insert(TABLE_WEBAPP)->data($webapp, false)->autocheck()->exec(false);
+ return $this->dao->lastInsertID();
+ }
+
+ /**
+ * Update app.
+ *
+ * @param int $webappID
+ * @access public
+ * @return void
+ */
+ public function update($webappID)
+ {
+ $data = fixer::input('post')->get();
+ $this->dao->update(TABLE_WEBAPP)->data($data, false)->where('id')->eq($webappID)->exec(false);
+ }
+
+ /**
+ * Create a web app.
+ *
+ * @access public
+ * @return void
+ */
+ public function create()
+ {
+ $data = fixer::input('post')
+ ->add('addedBy', $this->app->user->account)
+ ->add('addType', 'custom')
+ ->add('addedDate', helper::now())
+ ->add('author', $this->app->user->account)
+ ->remove('files')->get();
+ $this->dao->insert(TABLE_WEBAPP)->data($data, false)
+ ->autocheck()
+ ->batchCheck($this->config->webapp->create->requiredFields, 'notempty')
+ ->exec(false);
+ if(!dao::isError())
+ {
+ $webappID = $this->dao->lastInsertID();
+ if($_FILES)
+ {
+ $fileTitle = $this->loadModel('file')->saveUpload('webapp', $webappID);
+ $this->dao->update(TABLE_WEBAPP)->set('icon')->eq(key($fileTitle))->where('id')->eq($webappID)->exec(false);
+ }
+ return $webappID;
+ }
+ }
+
+ /**
+ * Get app modules.
+ *
+ * @access public
+ * @return void
+ */
+ public function getModules()
+ {
+ $modules = $this->tree->getOptionMenu(0, 'webapp');
+ $modules[0] = (count($modules) == 1) ? $this->lang->webapp->noModule : $this->lang->webapp->allModule;
+
+ return $modules;
+ }
+}
diff --git a/module/webapp/view/create.html.php b/module/webapp/view/create.html.php
new file mode 100644
index 0000000000..690264ed3d
--- /dev/null
+++ b/module/webapp/view/create.html.php
@@ -0,0 +1,48 @@
+
+ * @package webapp
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+?>
+
+
+
diff --git a/module/webapp/view/edit.html.php b/module/webapp/view/edit.html.php
new file mode 100644
index 0000000000..28aa8cffea
--- /dev/null
+++ b/module/webapp/view/edit.html.php
@@ -0,0 +1,59 @@
+
+ * @package webapp
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+?>
+
+
+
+
+
+ | webapp->size?> |
+ webapp->sizeList, $webapp->size, "class='select-3'")?> |
+
+
+ | webapp->height?> |
+ size, "class='text-3'")?> |
+
+
+
+
+
diff --git a/module/webapp/view/index.html.php b/module/webapp/view/index.html.php
new file mode 100644
index 0000000000..19a2e460a5
--- /dev/null
+++ b/module/webapp/view/index.html.php
@@ -0,0 +1,62 @@
+
+ * @package webapp
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+?>
+
+
+
+
+
+
+
+ name";?>
+
+ |
+ desc;?>
+
+ webapp->author} : {$webapp->author} ";
+ echo "{$lang->webapp->addType}: {$lang->webapp->addTypeList[$webapp->addType]} ";
+ ?>
+
+ |
+
+ id"), $lang->webapp->uninstall, 'hiddenwin', "class='button-c'");
+ $url = $webapp->addType == 'custom' ? $webapp->url : $config->webapp->url . "/webapp-showapp-{$webapp->appid}.html";
+ $method = '';
+ $popup = '';
+ $target = '_self';
+ if($webapp->target == 'blank') $target = '_blank';
+ if($webapp->target == 'inline')$method = "toggleShowapp($webapp->id);";
+ if($webapp->target == 'popup')
+ {
+ list($width, $height) = explode('x', $webapp->size);
+ $method = "popup($width, $height);";
+ $popup = 'popup';
+ }
+ $useAppCode = html::a($url, $lang->webapp->useapp, $target, "id='useapp$webapp->id' class='button-c $popup' onclick='addView($webapp->id);$method'");
+ $editAppCode = html::a(inlink('edit', "webappID=$webapp->id"), $lang->edit, '', "class='button-c webapp'");
+ echo $useAppCode . $editAppCode . $uninstallCode;
+ ?>
+ |
+
+
+
+ |
+
+
+
+
diff --git a/module/webapp/view/install.html.php b/module/webapp/view/install.html.php
new file mode 100644
index 0000000000..96ca0f2aea
--- /dev/null
+++ b/module/webapp/view/install.html.php
@@ -0,0 +1,27 @@
+
+ * @package webapp
+ * @version $Id$
+ * @link http://www.zentao.net
+ */
+?>
+
+