Merge branch 'master' of github.com:easysoft/zentaopms

This commit is contained in:
z
2020-07-22 17:06:51 +08:00
25 changed files with 308 additions and 122 deletions
+3
View File
@@ -1,3 +1,6 @@
ALTER TABLE `zt_doccontent` CHANGE `content` `content` longtext NOT NULL AFTER `digest`;
update zt_storystage as a, zt_story as b set a.stage = 'closed', b.stage = 'closed' where a.story = b.id and b.status = 'closed';
update zt_story set stage = 'closed' where status = 'closed';
+24
View File
@@ -800,6 +800,10 @@ class baseJS
*/
static public function alert($message = '', $full = true)
{
global $app;
if($app->viewType == 'json') return json_encode(array('message' => $message));
return self::start($full) . "alert('" . $message . "')" . self::end() . self::resetForm();
}
@@ -828,6 +832,10 @@ class baseJS
*/
static public function error($message, $full = true)
{
global $app;
if($app->viewType == 'json') return json_encode(array('message' => $message));
$alertMessage = '';
if(is_array($message))
{
@@ -871,6 +879,18 @@ class baseJS
*/
static public function confirm($message = '', $okURL = '', $cancleURL = '', $okTarget = "self", $cancleTarget = "self")
{
global $app;
if($app->viewType == 'json')
{
$output['message'] = $message;
$output['okURL'] = common::getSysURL() . $okURL;
$output['cancleURL'] = common::getSysURL() . $cancleURL;
$output['okTarget'] = $okTarget;
$output['cancleTarget'] = $cancleTarget;
return json_encode($output);
}
$js = self::start();
$confirmAction = '';
@@ -919,6 +939,8 @@ EOT;
*/
static public function locate($url, $target = "self")
{
global $app;
/* If the url if empty, goto the home page. */
if(!$url)
{
@@ -926,6 +948,8 @@ EOT;
$url = $config->webRoot;
}
if($app->viewType == 'json') return json_encode(array('locate' => common::getSysURL() . $url));
$js = self::start();
if(strtolower($url) == "back")
{
+14 -11
View File
@@ -482,6 +482,8 @@ class project extends control
*/
public function importBug($projectID = 0, $browseType = 'all', $param = 0, $recTotal = 0, $recPerPage = 30, $pageID = 1)
{
$this->app->loadConfig('task');
if(!empty($_POST))
{
$mails = $this->project->importBug($projectID);
@@ -605,17 +607,18 @@ class project extends control
$this->loadModel('search')->setSearchParams($this->config->bug->search);
/* Assign. */
$this->view->title = $title;
$this->view->position = $position;
$this->view->pager = $pager;
$this->view->bugs = $bugs;
$this->view->recTotal = $pager->recTotal;
$this->view->recPerPage = $pager->recPerPage;
$this->view->browseType = $browseType;
$this->view->param = $param;
$this->view->users = $users;
$this->view->project = $this->project->getByID($projectID);
$this->view->projectID = $projectID;
$this->view->title = $title;
$this->view->position = $position;
$this->view->pager = $pager;
$this->view->bugs = $bugs;
$this->view->recTotal = $pager->recTotal;
$this->view->recPerPage = $pager->recPerPage;
$this->view->browseType = $browseType;
$this->view->param = $param;
$this->view->users = $users;
$this->view->project = $this->project->getByID($projectID);
$this->view->projectID = $projectID;
$this->view->requiredFields = explode(',', $this->config->task->create->requiredFields);
$this->display();
}
+43 -7
View File
@@ -1468,12 +1468,20 @@ class projectModel extends model
$showAllModule = isset($this->config->project->task->allModule) ? $this->config->project->task->allModule : '';
$modules = $this->loadModel('tree')->getTaskOptionMenu($projectID, 0, 0, $showAllModule ? 'allModule' : '');
$project = $this->getByID($projectID);
$requiredFields = ',' . $this->config->task->create->requiredFields . ',';
if($project->type == 'ops') $requiredFields = str_replace(',story,', ',', $requiredFields);
$requiredFields = trim($requiredFields, ',');
$bugToTasks = fixer::input('post')->get();
$bugs = $this->bug->getByList(array_keys($bugToTasks->import));
foreach($bugToTasks->import as $key => $value)
{
$bug = $bugs[$key];
$bug = zget($bugs, $key, '');
if(empty($bug)) continue;
$task = new stdClass();
$task->bug = $bug;
$task->project = $projectID;
$task->story = $bug->story;
$task->storyVersion = $bug->storyVersion;
@@ -1483,22 +1491,50 @@ class projectModel extends model
$task->type = 'devel';
$task->pri = $bugToTasks->pri[$key];
$task->deadline = $bugToTasks->deadline[$key];
$task->estimate = $bugToTasks->estimate[$key];
$task->consumed = 0;
$task->assignedTo = '';
$task->status = 'wait';
$task->openedDate = $now;
$task->openedBy = $this->app->user->account;
if(!empty($bugToTasks->estimate[$key]))
{
$task->estimate = $bugToTasks->estimate[$key];
$task->left = $task->estimate;
}
if($task->estimate !== '') $task->left = $task->estimate;
if(strpos($requiredFields, 'deadline') !== false and $task->deadline == '0000-00-00') $task->deadline = '';
if(!empty($bugToTasks->assignedTo[$key]))
{
$task->assignedTo = $bugToTasks->assignedTo[$key];
$task->assignedDate = $now;
}
/* Check task required fields. */
foreach(explode(',', $requiredFields) as $field)
{
if(empty($field)) continue;
if(!isset($task->$field)) continue;
if(!empty($task->$field)) continue;
if($field == 'estimate' and strlen(trim($task->estimate)) != 0) continue;
dao::$errors['message'][] = sprintf($this->lang->error->notempty, $this->lang->task->$field);
return false;
}
if(!preg_match("/^[0-9]+(.[0-9]{1,3})?$/", $task->estimate))
{
dao::$errors['message'][] = $this->lang->task->error->estimateNumber;
return false;
}
$tasks[$key] = $task;
}
foreach($tasks as $key => $task)
{
$bug = $task->bug;
unset($task->bug);
if(!$bug->confirmed) $this->dao->update(TABLE_BUG)->set('confirmed')->eq(1)->where('id')->eq($bug->id)->exec();
$this->dao->insert(TABLE_TASK)->data($task)->checkIF($bugToTasks->estimate[$key] != '', 'estimate', 'float')->exec();
$this->dao->insert(TABLE_TASK)->data($task)->checkIF($task->estimate != '', 'estimate', 'float')->exec();
if(dao::isError())
{
+5 -5
View File
@@ -27,7 +27,7 @@ var browseType = '<?php echo $browseType;?>';
<div id='queryBox' data-module='importBug' class='show'></div>
</div>
<form class='main-table' method='post' target='hiddenwin' id='importBugForm' data-ride='table'>
<table class='table has-sort-head table-fixed'>
<table class='table table-form has-sort-head table-fixed'>
<thead>
<tr>
<th class='c-id'>
@@ -40,10 +40,10 @@ var browseType = '<?php echo $browseType;?>';
<th class='w-pri'> <?php echo $lang->priAB;?></th>
<th><?php echo $lang->bug->title;?></th>
<th class='w-80px'><?php echo $lang->bug->statusAB;?></th>
<th class='w-100px'><?php echo $lang->task->pri;?></th>
<th class='w-150px'><?php echo $lang->task->assignedTo;?></th>
<th class='w-80px'><?php echo $lang->task->estimate;?></th>
<th class='w-120px'><?php echo $lang->task->deadline;?></th>
<th class='w-100px <?php echo in_array('pri', $requiredFields) ? 'required' : ''?>'><?php echo $lang->task->pri;?></th>
<th class='w-150px <?php echo in_array('assignedTo', $requiredFields) ? 'required' : ''?>'><?php echo $lang->task->assignedTo;?></th>
<th class='w-80px <?php echo in_array('estimate', $requiredFields) ? 'required' : ''?>'><?php echo $lang->task->estimate;?></th>
<th class='w-120px <?php echo in_array('deadline', $requiredFields) ? 'required' : ''?>'><?php echo $lang->task->deadline;?></th>
</tr>
</thead>
<tbody>
+11 -4
View File
@@ -1114,7 +1114,7 @@ class storyModel extends model
/* Update parent story status. */
if($oldStory->parent > 0) $this->updateParentStatus($storyID, $oldStory->parent);
$this->setStage($storyID);
if(!dao::isError()) $this->loadModel('score')->create('story', 'close', $storyID);
return common::createChanges($oldStory, $story);
}
@@ -1183,7 +1183,7 @@ class storyModel extends model
{
/* Update parent story status. */
if($oldStory->parent > 0) $this->updateParentStatus($storyID, $oldStory->parent);
$this->setStage($storyID);
$allChanges[$storyID] = common::createChanges($oldStory, $story);
}
else
@@ -1437,9 +1437,7 @@ class storyModel extends model
$this->dao->delete()->from(TABLE_STORYSTAGE)->where('story')->eq($storyID)->exec();
$story = $this->dao->findById($storyID)->from(TABLE_STORY)->fetch();
if(!empty($story->stagedBy)) return false;
if($story->status == 'closed') $this->dao->update(TABLE_STORY)->set('stage')->eq('closed')->where('id')->eq($storyID)->exec();
$product = $this->dao->findById($story->product)->from(TABLE_PRODUCT)->fetch();
$projects = $this->dao->select('t1.project,t3.branch')->from(TABLE_PROJECTSTORY)->alias('t1')
@@ -1457,6 +1455,15 @@ class storyModel extends model
foreach($plans as $branch) $stages[$branch] = 'planned';
}
/* When the status is closed, phase = is also changed to closed. */
if($story->status == 'closed')
{
$this->dao->update(TABLE_STORY)->set('stage')->eq('closed')->where('id')->eq($storyID)->exec();
foreach($stages as $branch => $stage) $this->dao->replace(TABLE_STORYSTAGE)->set('story')->eq($storyID)->set('branch')->eq($branch)->set('stage')->eq('closed')->exec();
foreach($projects as $project => $branch) $this->dao->replace(TABLE_STORYSTAGE)->set('story')->eq($storyID)->set('branch')->eq($branch)->set('stage')->eq('closed')->exec();
return false;
}
/* If no projects, in plan, stage is planned. No plan, wait. */
if(!$projects)
{
+1
View File
@@ -201,6 +201,7 @@ $lang->task->error = new stdclass();
$lang->task->error->totalNumber = '"Total Cost" must be numbers.';
$lang->task->error->consumedNumber = '"Verbraucht" muss eine Zahl sein.';
$lang->task->error->estimateNumber = '"Stunden" müss eine Zahl sein.';
$lang->task->error->leftNumber = '"Left" must be numbers.';
$lang->task->error->recordMinus = 'Work hours should not be negative number.';
$lang->task->error->consumedSmall = '"Genutzt" muss larger than before.';
$lang->task->error->consumedThisTime = 'Bitte geben Sie die Stunden an';
+1
View File
@@ -201,6 +201,7 @@ $lang->task->error = new stdclass();
$lang->task->error->totalNumber = '"Total Cost" must be numbers.';
$lang->task->error->consumedNumber = '"Current Cost" must be numbers.';
$lang->task->error->estimateNumber = '"Estimates" must be numbers.';
$lang->task->error->leftNumber = '"Left" must be numbers.';
$lang->task->error->recordMinus = 'Work hours should not be negative number.';
$lang->task->error->consumedSmall = '"Total Cost" must be > the last number.';
$lang->task->error->consumedThisTime = 'Please enter "Hours Cost"';
+1
View File
@@ -201,6 +201,7 @@ $lang->task->error = new stdclass();
$lang->task->error->totalNumber = '"Total Cost" must be numbers.';
$lang->task->error->consumedNumber = '"Coût" doit être numérique.';
$lang->task->error->estimateNumber = '"Estimé" doit être numérique.';
$lang->task->error->leftNumber = '"Entrez" doit être numérique.';
$lang->task->error->recordMinus = 'Work hours should not be negative number.';
$lang->task->error->consumedSmall = '"Coût Total" doit être > au dernier chiffre.';
$lang->task->error->consumedThisTime = 'Entrez le "Coût en Heures"';
+1
View File
@@ -201,6 +201,7 @@ $lang->task->error = new stdclass();
$lang->task->error->totalNumber = '"Total Cost" must be numbers.';
$lang->task->error->consumedNumber = '"Giờ làm" phải là số.';
$lang->task->error->estimateNumber = '"Dự tính" phải là số.';
$lang->task->error->leftNumber = '"Left" must be numbers.';
$lang->task->error->recordMinus = 'Giờ làm không nên là số âm';
$lang->task->error->consumedSmall = '"Tổng giờ làm" phải là > số cuối cùng.';
$lang->task->error->consumedThisTime = 'Vui lòng nhập "Số giờ làm"';
+2 -1
View File
@@ -200,7 +200,8 @@ $lang->task->cannotDeleteParent = '不能删除父任务。';
$lang->task->error = new stdclass();
$lang->task->error->totalNumber = '"总计消耗"必须为数字';
$lang->task->error->consumedNumber = '"本次消耗"必须为数字';
$lang->task->error->estimateNumber = '"预计剩余"必须为数字';
$lang->task->error->estimateNumber = '"最初预计"必须为数字';
$lang->task->error->leftNumber = '"预计剩余"必须为数字';
$lang->task->error->recordMinus = '工时不能为负数';
$lang->task->error->consumedSmall = '"总计消耗"必须大于之前消耗';
$lang->task->error->consumedThisTime = '请填写"工时"';
+2 -2
View File
@@ -1296,7 +1296,7 @@ class taskModel extends model
foreach($record->consumed as $id => $item) $record->consumed[$id] = trim($item);
foreach($record->left as $id => $item) $record->left[$id] = trim($item);
foreach($record->consumed as $id => $item) if(!is_numeric($item) and !empty($item)) dao::$errors[] = 'ID #' . $id . ' ' . $this->lang->task->error->totalNumber;
foreach($record->left as $id => $item) if(!is_numeric($item) and !empty($item)) dao::$errors[] = 'ID #' . $id . ' ' . $this->lang->task->error->estimateNumber;
foreach($record->left as $id => $item) if(!is_numeric($item) and !empty($item)) dao::$errors[] = 'ID #' . $id . ' ' . $this->lang->task->error->leftNumber;
if(dao::isError()) return false;
$estimates = array();
@@ -1647,7 +1647,7 @@ class taskModel extends model
if(!is_numeric($task->left))
{
dao::$errors[] = $this->lang->task->error->estimateNumber;
dao::$errors[] = $this->lang->task->error->leftNumber;
return false;
}
+3
View File
@@ -149,6 +149,7 @@ class todo extends control
$todo = $this->todo->getById($todoID);
if($todo->private and $this->app->user->account != $todo->account) die('private');
unset($this->lang->todo->typeList['cycle']);
$todo->date = date("Y-m-d", strtotime($todo->date));
$this->view->title = $this->lang->todo->common . $this->lang->colon . $this->lang->todo->edit;
$this->view->position[] = $this->lang->todo->common;
@@ -206,6 +207,8 @@ class todo extends control
$countInputVars = count($editedTodos) * $columns;
$showSuhosinInfo = common::judgeSuhosinSetting($countInputVars);
unset($this->lang->todo->typeList['cycle']);
/* Set Custom*/
foreach(explode(',', $this->config->todo->list->customBatchEditFields) as $field) $customFields[$field] = $this->lang->todo->$field;
$this->view->customFields = $customFields;
+4
View File
@@ -0,0 +1,4 @@
$(function()
{
loadList($('#type').val());
});
+15 -5
View File
@@ -171,13 +171,17 @@ class todoModel extends model
$todo = fixer::input('post')
->cleanInt('pri, begin, end, private')
->add('account', $oldTodo->account)
->setIF(in_array($oldTodo->type, array('bug', 'task', 'story')), 'name', '')
->setIF(in_array($this->post->type, array('bug', 'task', 'story')), 'name', '')
->setIF($this->post->type == 'bug' and $this->post->bug, 'idvalue', $this->post->bug)
->setIF($this->post->type == 'task' and $this->post->task, 'idvalue', $this->post->task)
->setIF($this->post->type == 'story' and $this->post->story, 'idvalue', $this->post->story)
->setIF($this->post->type == 'feedback' and $this->post->feedback, 'idvalue', $this->post->feedback)
->setIF($this->post->date == false, 'date', '2030-01-01')
->setIF($this->post->begin == false, 'begin', '2400')
->setIF($this->post->end == false, 'end', '2400')
->setDefault('private', 0)
->stripTags($this->config->todo->editor->edit['id'], $this->config->allowedTags)
->remove('uid')
->remove('bug, task, story, feedback, uid')
->get();
if($todo->end < $todo->begin)
@@ -214,6 +218,10 @@ class todoModel extends model
$this->dao->update(TABLE_TODO)->data($todo)
->autoCheck()
->checkIF($todo->type == 'custom', $this->config->todo->edit->requiredFields, 'notempty')
->checkIF($todo->type == 'bug' and $todo->idvalue == 0, 'idvalue', 'notempty')
->checkIF($todo->type == 'task' and $todo->idvalue == 0, 'idvalue', 'notempty')
->checkIF($todo->type == 'story' and $todo->idvalue == 0, 'idvalue', 'notempty')
->checkIF($todo->type == 'feedback' and $todo->idvalue == 0, 'idvalue', 'notempty')
->where('id')->eq($todoID)
->exec();
if(!dao::isError())
@@ -263,12 +271,14 @@ class todoModel extends model
foreach($todos as $todoID => $todo)
{
$oldTodo = $oldTodos[$todoID];
if($oldTodo->type == 'bug' or $oldTodo->type == 'task') $oldTodo->name = '';
if($oldTodo->type == 'bug' or $oldTodo->type == 'task' or $oldTodo->type == 'story' or $oldTodo->type == 'feedback') $oldTodo->name = '';
$this->dao->update(TABLE_TODO)->data($todo)
->autoCheck()
->checkIF($todo->type == 'custom', $this->config->todo->edit->requiredFields, 'notempty')
->checkIF($todo->type == 'bug', 'idvalue', 'notempty')
->checkIF($todo->type == 'task', 'idvalue', 'notempty')
->checkIF($todo->type == 'bug' and $todo->idvalue == 0, 'idvalue', 'notempty')
->checkIF($todo->type == 'task' and $todo->idvalue == 0, 'idvalue', 'notempty')
->checkIF($todo->type == 'story' and $todo->idvalue == 0, 'idvalue', 'notempty')
->checkIF($todo->type == 'feedback' and $todo->idvalue == 0, 'idvalue', 'notempty')
->where('id')->eq($todoID)
->exec();
+3 -4
View File
@@ -36,7 +36,7 @@
<tr class='text-center'>
<th class='w-40px'> <?php echo $lang->idAB;?></th>
<th class='w-100px'> <?php echo $lang->todo->date;?></th>
<th class='w-80px'> <?php echo $lang->todo->type;?></th>
<th class='w-110px'> <?php echo $lang->todo->type;?></th>
<th class='w-100px<?php echo zget($visibleFields, 'pri', ' hidden')?>'> <?php echo $lang->todo->pri;?></th>
<th><?php echo $lang->todo->name;?></th>
<th <?php echo zget($visibleFields, 'desc', "class='hidden'")?>><?php echo $lang->todo->desc;?></th>
@@ -50,12 +50,11 @@
<td><?php echo $todo->id . html::hidden("todoIDList[$todo->id]", $todo->id);?></td>
<td><?php echo html::input("dates[$todo->id]", $todo->date, "class='form-control form-date'");?></td>
<td class='text-center'>
<?php echo zget($lang->todo->typeList, $todo->type);?>
<?php echo html::hidden("types[$todo->id]", $todo->type);?>
<?php echo html::select("types[$todo->id]", $lang->todo->typeList, $todo->type, "onchange='loadList(this.value, " . $todo->id . ")' class='form-control'");?>
</td>
<td style='overflow:visible' <?php echo zget($visibleFields, 'pri', "class='hidden'")?>><?php echo html::select("pris[$todo->id]", $lang->todo->priList, $todo->pri, "class='form-control chosen'");?></td>
<td style='overflow:visible'>
<div id='<?php echo "nameBox" . $todo->id;?>' class='hidden'><? echo html::input("names[$todo->id]", '', "class='text-left form-control hiddenwin'"); ?></div>
<div id='<?php echo "nameBox" . $todo->id;?>' class='hidden'><?php echo html::input("names[$todo->id]", $todo->name, "class='text-left form-control hiddenwin'"); ?></div>
<div class='<?php echo "nameBox" . $todo->id;?> text-left'>
<?php
if($todo->type == 'custom' or $todo->type == 'cycle')
+4 -9
View File
@@ -85,9 +85,8 @@
<?php endif;?>
<div class="row form-group">
<label class="col-sm-1"><?php echo $lang->todo->type;?></label>
<div class="col-sm-10 todoType">
<input type='hidden' name='type' value='<?php echo $todo->type;?>' />
<?php echo $lang->todo->typeList[$todo->type];?>
<div class="col-sm-2">
<?php echo html::select('type', $lang->todo->typeList, $todo->type, 'onchange="loadList(this.value);" class="form-control"');?>
</div>
</div>
<div class="row form-group">
@@ -99,12 +98,8 @@
<div class="row form-group">
<label class="col-sm-1"><?php echo $lang->todo->name;?></label>
<div class="col-sm-10">
<div id='nameBox' class='required'>
<?php
$readType = ($todo->type == 'bug' or $todo->type == 'task') ? 'readonly' : '';
echo html::input('name', $todo->name, "$readType class='form-control'");
?>
</div>
<div id='nameBox' class='hidden'><?php echo html::input('name', $todo->name, "class='form-control'");?></div>
<div class='nameBox required'><?php echo html::input('name', $todo->name, "class='form-control'");?></div>
</div>
</div>
<div class="row form-group">
+146 -59
View File
@@ -87,12 +87,12 @@
function _addUnit(val, unit) {
unit = unit || 'px';
return val && /^\d+$/.test(val) ? val + unit : val;
return val && /^[\d\.]+$/.test(val) ? val + unit : val;
}
function _removeUnit(val) {
var match;
return val && (match = /(\d+)/.exec(val)) ? parseInt(match[1], 10) : 0;
return val && (match = /([\d\.]+)/.exec(val)) ? parseInt(match[1], 10) : 0;
}
function _escape(val) {
@@ -320,6 +320,9 @@
],
a: ['id', 'class', 'href', 'target', 'name'],
embed: ['id', 'class', 'src', 'width', 'height', 'type', 'loop', 'autostart', 'quality', '.width', '.height', 'align', 'allowscriptaccess'],
audio: ['id', 'class', 'width', 'src', 'height', 'loop', 'preload', 'autoplay', 'controls', 'crossorigin', 'currentTime', 'duration', 'muted'],
video: ['id', 'class', 'width', 'src', 'height', 'loop', 'preload', 'autoplay', 'controls', 'crossorigin', 'currentTime', 'duration', 'muted', 'buffered', 'playsinline', 'played', 'poster'],
source: ['src', 'type'],
img: ['id', 'class', 'src', 'width', 'height', 'border', 'alt', 'title', 'align', '.width', '.height', '.border'],
'p,ol,ul,li,blockquote,h1,h2,h3,h4,h5,h6': [
'id', 'class', 'align', '.text-align', '.color', '.background-color', '.font-size', '.font-family', '.background',
@@ -656,13 +659,14 @@
return list;
}
function _getAttrList(tag) {
function _getAttrList(tag, emptyValue) {
var list = {},
reg = /\s+(?:([\w\-:]+)|(?:([\w\-:]+)=([^\s"'<>]+))|(?:([\w\-:"]+)="([^"]*)")|(?:([\w\-:"]+)='([^']*)'))(?=(?:\s|\/|>)+)/g,
match;
if (emptyValue === undefined) emptyValue = '';
while((match = reg.exec(tag))) {
var key = (match[1] || match[2] || match[4] || match[6]).toLowerCase(),
val = (match[2] ? match[3] : (match[4] ? match[5] : match[7])) || '';
val = (match[2] ? match[3] : (match[4] ? match[5] : match[7])) || emptyValue;
list[key] = val;
}
return list;
@@ -877,11 +881,12 @@
prevTagIsBlockEnd = null;
}
if(attr !== '') {
var attrMap = _getAttrList(full);
var attrMap = _getAttrList(full, true);
if(tagName === 'font') {
var fontStyleMap = {},
fontStyle = '';
_each(attrMap, function(key, val) {
if(val === true) val = '';
if(key === 'color') {
fontStyleMap.color = val;
delete attrMap[key];
@@ -913,6 +918,7 @@
attrMap.style = fontStyle;
}
_each(attrMap, function(key, val) {
if(val === true) val = '';
if(_FILL_ATTR_MAP[key]) {
attrMap[key] = key;
}
@@ -940,7 +946,11 @@
});
attr = '';
_each(attrMap, function(key, val) {
if(key === 'style' && val === '') {
if(val === false || (key === 'style' && val === '')) {
return;
}
if (val === true) {
attr += ' ' + key;
return;
}
val = val.replace(/"/g, '&quot;');
@@ -975,43 +985,101 @@
}
function _mediaType(src) {
if(/\.(rm|rmvb)(\?|$)/i.test(src)) {
return 'audio/x-pn-realaudio-plugin';
if(/\.(mp4)(\?|$)/i.test(src)) {
return 'video/mp4';
}
if(/\.(swf|flv)(\?|$)/i.test(src)) {
return 'application/x-shockwave-flash';
if(/\.(webm)(\?|$)/i.test(src)) {
return 'video/webm';
}
return 'video/x-ms-asf-plugin';
if(/\.(ogg)(\?|$)/i.test(src)) {
return 'video/ogg';
}
if(/\.(mov)(\?|$)/i.test(src)) {
return 'video/quicktime';
}
if(/\.(mp3)(\?|$)/i.test(src)) {
return 'audio/mp3';
}
if(/\.(wav)(\?|$)/i.test(src)) {
return 'audio/wav';
}
if(/\.(flac)(\?|$)/i.test(src)) {
return 'audio/flac';
}
return 'video/application';
}
function _mediaClass(type) {
if(/realaudio/i.test(type)) {
return 'ke-rm';
if(/audio/i.test(type)) {
return 'ke-audio';
}
if(/flash/i.test(type)) {
return 'ke-flash';
if(/video/i.test(type)) {
return 'ke-video';
}
return 'ke-media';
}
function _mediaAttrs(srcTag) {
return _getAttrList(unescape(srcTag));
var srcs = [];
srcTag = unescape(srcTag).replace(/<source [^>]*>/ig, function(sourceTag) {
var $source = $(sourceTag);
var src = $source.attr('src');
var type = $source.attr('type');
if(type) src += '#' + type;
srcs.push(src);
return '';
});
var attrs = _getAttrList(srcTag);
if(srcs.length) attrs.src = srcs.join(',');
return attrs;
}
function _mediaEmbed(attrs) {
var html = '<embed ';
_each(attrs, function(key, val) {
html += key + '="' + val + '" ';
});
html += '/>';
return html;
function _mediaEmbed(attrs, mediaType) {
var htmls;
if(mediaType === 'media' || mediaType === 'video' || mediaType === 'audio') {
mediaType = mediaType === 'video' || (attrs.type && attrs.type.indexOf('video') === 0) ? 'video' : 'audio';
htmls = [
'<', mediaType, ' '
];
var srcs = (attrs.src || '').split(',');
_each(attrs, function(key, val) {
if (key === 'src' || val === false) {
return;
}
if (val === true || /^(controls|autoplay|loop|muted)$/i.test(key)) {
if (val !== 'false') {
htmls.push(key + ' ');
}
} else {
htmls.push(key, '="', val, '" ');
}
});
if (srcs.length > 1) {
htmls.push('>');
_each(srcs, function(_, val) {
var srcType = val.split('#');
htmls.push('<source src="', srcType[0], '"', srcType.length > 1 ? (' type="' + srcType[1] + '"') : '', ' />');
});
htmls.push('</', mediaType, '>');
} else {
if(srcs.length) htmls.push('src="', srcs[0], '" ');
htmls.push('/>');
}
} else {
htmls = ['<embed '];
_each(attrs, function(key, val) {
htmls.push(key, '="', val, '" ');
});
htmls.push('/>');
}
return htmls.join('');
}
function _mediaImg(blankPath, attrs) {
var width = attrs.width,
height = attrs.height,
type = attrs.type || _mediaType(attrs.src),
srcTag = _mediaEmbed(attrs),
srcTag = _mediaEmbed(attrs, type),
style = '';
if(/\D/.test(width)) {
style += 'width:' + width + ';';
@@ -3730,14 +3798,14 @@
var self = this;
updateProp = _undef(updateProp, true);
if(x !== null) {
x = x < 0 ? 0 : _addUnit(x);
x = x < 0 ? 0 : _addUnit(Math.floor(x));
self.div.css('left', x);
if(updateProp) {
self.x = x;
}
}
if(y !== null) {
y = y < 0 ? 0 : _addUnit(y);
y = y < 0 ? 0 : _addUnit(Math.floor(y));
self.div.css('top', y);
if(updateProp) {
self.y = y;
@@ -3834,30 +3902,17 @@
'img {border:0;}',
'noscript {display:none;}',
'table.ke-zeroborder td {border:1px dotted #AAA;}',
'img.ke-flash {',
'img.ke-media, img.ke-audio, img.ke-video {',
' border:1px solid #AAA;',
' background-image:url(' + themesPath + 'common/flash.gif);',
' background-position:center center;',
' background-repeat:no-repeat;',
' width:100px;',
' height:100px;',
'}',
'img.ke-rm {',
' border:1px solid #AAA;',
' background-image:url(' + themesPath + 'common/rm.gif);',
' background-position:center center;',
' background-repeat:no-repeat;',
' width:100px;',
' height:100px;',
'}',
'img.ke-media {',
' border:1px solid #AAA;',
' background-image:url(' + themesPath + 'common/media.gif);',
' background-image:url(' + themesPath + 'common/media.png);',
' background-position:center center;',
' background-repeat:no-repeat;',
' background-color:#f1f1f1;',
' width:100px;',
' height:100px;',
'}',
'img.ke-audio {background-image:url(' + themesPath + 'common/audio.png); height: 54px!important}',
'img.ke-video {background-image:url(' + themesPath + 'common/video.png)}',
'img.ke-anchor {',
' border:1px dashed #666;',
' width:16px;',
@@ -6088,7 +6143,7 @@
};
self.plugin.getSelectedMedia = function() {
return _getImageFromRange(self.edit.cmd.range, function(img) {
return img[0].className == 'ke-media' || img[0].className == 'ke-rm';
return img[0].className == 'ke-media' || img[0].className == 'ke-video' || img[0].className == 'ke-audio';
});
};
self.plugin.getSelectedAnchor = function() {
@@ -6246,7 +6301,7 @@
return html.replace(/(<(?:noscript|noscript\s[^>]*)>)([\s\S]*?)(<\/noscript>)/ig, function($0, $1, $2, $3) {
return $1 + _unescape($2).replace(/\s+/g, ' ') + $3;
})
.replace(/<img[^>]*class="?ke-(flash|rm|media)"?[^>]*>/ig, function(full) {
.replace(/<img[^>]*class="?ke-(media|video|audio)"?[^>]*>/ig, function(full, $1) {
var imgAttrs = _getAttrList(full);
var styles = _getCssList(imgAttrs.style || '');
var attrs = _mediaAttrs(imgAttrs['data-ke-tag']);
@@ -6260,7 +6315,8 @@
}
attrs.width = _undef(imgAttrs.width, width);
attrs.height = _undef(imgAttrs.height, height);
return _mediaEmbed(attrs);
return _mediaEmbed(attrs, $1);
})
.replace(/<img[^>]*class="?ke-anchor"?[^>]*>/ig, function(full) {
var imgAttrs = _getAttrList(full);
@@ -6301,6 +6357,26 @@
attrs.height = _undef(attrs.height, 0);
return _mediaImg(self.themesPath + 'common/blank.gif', attrs);
})
.replace(/<(video|audio)[^>]*>((\s*<source [^>]*>\s*)*)(?:<\/(video|audio)>)?/ig, function(full, $1, $2) {
var attrs = _getAttrList($2 ? full.replace($2, '') : full);
if($2) {
var srcs = [];
$($2).filter('source').each(function() {
var $source = $(this);
var src = $source.attr('src');
var type = $source.attr('type');
if(type) src += '#' + type;
srcs.push(src);
});
attrs.src = srcs.join(',');
} else {
attrs.src = _undef(attrs.src, '');
}
attrs.width = _undef(attrs.width, 0);
attrs.height = _undef(attrs.height, 0);
attrs.type = $1;
return _mediaImg(self.themesPath + 'common/blank.gif', attrs);
})
.replace(/<a[^>]*name="([^"]+)"[^>]*>(?:<\/a>)?/ig, function(full) {
var attrs = _getAttrList(full);
if(attrs.href !== undefined) {
@@ -6458,11 +6534,13 @@ KindEditor.lang({
'flash.upload': '上传',
'flash.viewServer': '文件空间',
'media.url': 'URL',
'media.urlTip': '多个 URL 使用英文逗号分隔',
'media.width': '宽度',
'media.height': '高度',
'media.autostart': '自动播放',
'media.upload': '上传',
'media.viewServer': '文件空间',
'media.controls': '播放控件',
'image.remoteImage': '网络图片',
'image.localImage': '本地上传',
'image.remoteUrl': '图片地址',
@@ -6699,6 +6777,7 @@ KindEditor.plugin('baidumap', function(K) {
var self = this,
name = 'baidumap',
lang = self.lang(name + '.');
var ak = self.options.baidumapAk || 'plddmxBud2dRsVAXHS7WLqqzQQTocDkO';
var mapWidth = K.undef(self.mapWidth, 558);
var mapHeight = K.undef(self.mapHeight, 360);
self.clickToolbar(name, function() {
@@ -6712,8 +6791,8 @@ KindEditor.plugin('baidumap', function(K) {
'</span>',
'</div>',
// right start
'<div class="ke-right">',
'<input type="checkbox" id="keInsertDynamicMap" name="insertDynamicMap" value="1" /> <label for="keInsertDynamicMap">' + lang.insertDynamicMap + '</label>',
'<div class="ke-right" style="margin-top: 2px">',
'<input type="checkbox" id="keInsertDynamicMap" name="insertDynamicMap" value="1" style="margin-top: 2px" /> <label for="keInsertDynamicMap">' + lang.insertDynamicMap + '</label>',
'</div>',
'<div class="ke-clearfix"></div>',
'</div>',
@@ -6732,8 +6811,8 @@ KindEditor.plugin('baidumap', function(K) {
var centerObj = map.getCenter();
var center = centerObj.lng + ',' + centerObj.lat;
var zoom = map.getZoom();
var url = [checkbox[0].checked ? self.pluginsPath + 'baidumap/index.html' : 'http://api.map.baidu.com/staticimage',
'?center=' + encodeURIComponent(center),
var url = [checkbox[0].checked ? self.pluginsPath + 'baidumap/index.html?ak=' + ak : 'http://api.map.baidu.com/staticimage/v2?ak=' + ak,
'&center=' + encodeURIComponent(center),
'&zoom=' + encodeURIComponent(zoom),
'&width=' + mapWidth,
'&height=' + mapHeight,
@@ -6761,7 +6840,7 @@ KindEditor.plugin('baidumap', function(K) {
searchBtn = K('[name="searchBtn"]', div),
checkbox = K('[name="insertDynamicMap"]', dialog.div),
win, doc;
var iframe = K('<iframe class="ke-textarea" frameborder="0" src="' + self.pluginsPath + 'baidumap/map.html" style="width:' + mapWidth + 'px;height:' + mapHeight + 'px;"></iframe>');
var iframe = K('<iframe class="ke-textarea" frameborder="0" src="' + self.pluginsPath + 'baidumap/map.html?ak=' + ak + '" style="width:' + mapWidth + 'px;height:' + mapHeight + 'px;"></iframe>');
function ready() {
win = iframe[0].contentWindow;
@@ -8133,7 +8212,7 @@ KindEditor.plugin('media', function(K) {
//url
'<div class="ke-dialog-row">',
'<label for="keUrl" style="width:60px;">' + lang.url + '</label>',
'<input class="ke-input-text" type="text" id="keUrl" name="url" value="" style="width:160px;" /> &nbsp;',
'<input class="ke-input-text" type="text" id="keUrl" name="url" value="" placeholder="' + lang.urlTip + '" style="width:160px;" /> &nbsp;',
'<input type="button" class="ke-upload-button" value="' + lang.upload + '" /> &nbsp;',
'<span class="ke-button-common ke-button-outer">',
'<input type="button" class="ke-button-common ke-button" name="viewServer" value="' + lang.viewServer + '" />',
@@ -8149,6 +8228,11 @@ KindEditor.plugin('media', function(K) {
'<label for="keHeight" style="width:60px;">' + lang.height + '</label>',
'<input type="text" id="keHeight" class="ke-input-text ke-input-number" name="height" value="400" maxlength="4" />',
'</div>',
//controls
'<div class="ke-dialog-row">',
'<label for="keControls">' + lang.controls + '</label>',
'<input type="checkbox" id="keControls" checked name="controls" value="true" /> ',
'</div>',
//autostart
'<div class="ke-dialog-row">',
'<label for="keAutostart">' + lang.autostart + '</label>',
@@ -8159,7 +8243,7 @@ KindEditor.plugin('media', function(K) {
var dialog = self.createDialog({
name: name,
width: 450,
height: 230,
height: 270,
title: self.lang(name),
body: html,
yesBtn: {
@@ -8188,8 +8272,8 @@ KindEditor.plugin('media', function(K) {
type: K.mediaType(url),
width: width,
height: height,
autostart: autostartBox[0].checked ? 'true' : 'false',
loop: 'true'
autoplay: !!autostartBox[0].checked,
controls: !!controlsBox[0].checked,
});
self.insertHtml(html).hideDialog().focus();
}
@@ -8201,6 +8285,7 @@ KindEditor.plugin('media', function(K) {
widthBox = K('[name="width"]', div),
heightBox = K('[name="height"]', div),
autostartBox = K('[name="autostart"]', div);
controlsBox = K('[name="controls"]', div);
urlBox.val('http://');
if(allowMediaUpload) {
@@ -8266,7 +8351,8 @@ KindEditor.plugin('media', function(K) {
urlBox.val(attrs.src);
widthBox.val(K.removeUnit(img.css('width')) || attrs.width || 0);
heightBox.val(K.removeUnit(img.css('height')) || attrs.height || 0);
autostartBox[0].checked = (attrs.autostart === 'true');
autostartBox[0].checked = (attrs.autoplay !== undefined && attrs.autoplay !== 'false');
controlsBox[0].checked = (attrs.controls !== undefined && attrs.controls !== 'false');
}
urlBox[0].focus();
urlBox[0].select();
@@ -9994,7 +10080,7 @@ KindEditor.plugin('wordpaste', function(K) {
* ZUI: Kindeditor plugin - zui
* http://openzui.com
* ========================================================================
* Copyright (c) 2019-2019 cnezsoft.com; Licensed MIT
* Copyright (c) 2019-2020 cnezsoft.com; Licensed MIT
* ======================================================================== */
$.each(['afterBlur', 'afterFocus', 'afterChange', 'afterTab'], function(_index, name) {
@@ -10059,7 +10145,7 @@ KindEditor.plugin('zui', function(K) {
* ZUI: Kindeditor plugin - placeholder
* http://openzui.com
* ========================================================================
* Copyright (c) 2019-2019 cnezsoft.com; Licensed MIT
* Copyright (c) 2019-2020 cnezsoft.com; Licensed MIT
* ======================================================================== */
KindEditor.EditorClass.prototype.setPlaceholder = function(placeholder, asHtml) {
@@ -10948,6 +11034,7 @@ KindEditor.plugin('table', function (K) {
newCell = newRow.insertCell(index),
isThead = newRow.parentNode.tagName === 'THEAD';
newCell.outerHTML = '<' + (isThead ? 'th' : 'td') + (newCell.rowSpan > 1 ? ' rowspan="' + newCell.rowSpan + '"' : '') + (newCell.colSpan > 1 ? ' colspan="' + newCell.colSpan + '"' : '') + ' style="' + (isThead ? 'background-color: #f1f1f1;' : '') + 'border: 1px solid ' + ((self.tableSetting && self.tableSetting.borderColor) || defaultTableBorderColor) + '">' + (K.IE ? '&nbsp;' : '<br />') + '</' + (isThead ? 'th' : 'td') + '>';
newCell = newRow.cells[index];
// 调整下一行的单元格index
index = _getCellIndex(table, newRow, newCell);
}
File diff suppressed because one or more lines are too long
Executable → Regular
+4 -2
View File
@@ -119,12 +119,14 @@ KindEditor.lang({
'flash.height' : 'الإرتفاع',
'flash.upload' : 'رفع',
'flash.viewServer' : 'أستعراض',
'media.url' : 'الرابط',
'media.url' : 'الرابط',
'media.urlTip': 'Multiple URLs are separated by commas',
'media.width' : 'العرض',
'media.height' : 'الإرتفاع',
'media.autostart' : 'تشغيل تلقائي',
'media.upload' : 'رفع',
'media.viewServer' : 'أستعراض',
'media.viewServer' : 'أستعراض',
'media.controls': 'Play controls',
'image.remoteImage' : 'إدراج الرابط',
'image.localImage' : 'رفع',
'image.remoteUrl' : 'الرابط',
Executable → Regular
+2
View File
@@ -120,11 +120,13 @@ KindEditor.lang({
'flash.upload' : 'Upload',
'flash.viewServer' : 'Browse',
'media.url' : 'URL',
'media.urlTip': 'Multiple URLs are separated by commas',
'media.width' : 'Width',
'media.height' : 'Height',
'media.autostart' : 'Auto start',
'media.upload' : 'Upload',
'media.viewServer' : 'Browse',
'media.controls': 'Play controls',
'image.remoteImage' : 'Insert URL',
'image.localImage' : 'Upload',
'image.remoteUrl' : 'URL',
+4 -2
View File
@@ -119,12 +119,14 @@ KindEditor.lang({
'flash.height' : 'Height',
'flash.upload' : 'Upload',
'flash.viewServer' : 'Browse',
'media.url' : 'URL',
'media.url' : 'URL',
'media.urlTip': 'Multiple URLs are separated by commas',
'media.width' : 'Width',
'media.height' : 'Height',
'media.autostart' : 'Auto start',
'media.upload' : 'Upload',
'media.viewServer' : 'Browse',
'media.viewServer' : 'Browse',
'media.controls': 'Play controls',
'image.remoteImage' : 'Insert URL',
'image.localImage' : 'Upload',
'image.remoteUrl' : 'URL',
+2 -4
View File
@@ -122,11 +122,13 @@ KindEditor.lang({
'flash.upload' : 'アップロード',
'flash.viewServer' : 'ファイルスペース',
'media.url' : 'URL',
'media.urlTip': '複数のURLはコンマで区切られます',
'media.width' : '幅',
'media.height' : '高さ',
'media.autostart' : '自動放送',
'media.upload' : 'アップロード',
'media.viewServer' : 'ファイルスペース',
'media.controls': '再生コントロール',
'image.remoteImage' : 'オンライン画像',
'image.localImage' : 'ローカルアップロード',
'image.remoteUrl' : '画像アドレス',
@@ -266,10 +268,6 @@ if (window.$ && $.zui && $.zui.lang) {
placeholder: 'エディターを使用して画像を貼り付けます。',
failMsg: '画像を貼り付けませんでした、後でやり直してください。',
uploadingHint: '画像をアップロード中、しばらくお待ちください...',
},
'zui.table': {
selectedItems: '<strong>{0}</strong> 選択',
attrTotal: '{0} 合計 <strong>{1}</strong>'
}
});
}
Executable → Regular
+4
View File
@@ -122,11 +122,13 @@ KindEditor.lang({
'flash.upload' : '上传',
'flash.viewServer' : '文件空间',
'media.url' : 'URL',
'media.urlTip': '多个 URL 使用英文逗号分隔',
'media.width' : '宽度',
'media.height' : '高度',
'media.autostart' : '自动播放',
'media.upload' : '上传',
'media.viewServer' : '文件空间',
'media.controls': '播放控件',
'image.remoteImage' : '网络图片',
'image.localImage' : '本地上传',
'image.remoteUrl' : '图片地址',
@@ -211,6 +213,8 @@ KindEditor.lang({
'FangSong_GB2312' : '仿宋_GB2312',
'KaiTi_GB2312' : '楷体_GB2312',
'SimHei' : '黑体',
'Source Han Sans': '思源黑体',
'Source Han Serif': '思源宋体',
'Microsoft YaHei' : '微软雅黑',
'Arial' : 'Arial',
'Arial Black' : 'Arial Black',
Executable → Regular
+2
View File
@@ -121,11 +121,13 @@ KindEditor.lang({
'flash.upload' : '上傳',
'flash.viewServer' : '瀏覽',
'media.url' : 'URL',
'media.urlTip': '多個 URL 使用英文逗號分隔',
'media.width' : '寬度',
'media.height' : '高度',
'media.autostart' : '自動播放',
'media.upload' : '上傳',
'media.viewServer' : '瀏覽',
'media.controls': '播放控件',
'image.remoteImage' : '網絡影像',
'image.localImage' : '上傳影像',
'image.remoteUrl' : '影像URL',