diff --git a/addons/devteam/config.php b/addons/devteam/config.php index bed2aa73..851a3460 100644 --- a/addons/devteam/config.php +++ b/addons/devteam/config.php @@ -1,36 +1,22 @@ +// | Author: molong // +---------------------------------------------------------------------- -return array( - 'title'=>array(//配置在表单中的键名 ,这个会是config[title] - 'title'=>'显示标题:',//表单的文字 - 'type'=>'text', //表单的类型:text、textarea、checkbox、radio、select等 - 'value'=>'SentCMS开发团队', //表单的默认值 - ), - 'width'=>array( - 'title'=>'显示宽度:', - 'type'=>'select', - 'options'=>array( - '1'=>'1格', - '2'=>'2格', - '4'=>'4格', - '6'=>'6格' - ), - 'value'=>'6' - ), - 'display'=>array( - 'title'=>'是否显示:', - 'type'=>'radio', - 'options'=>array( - '1'=>'显示', - '0'=>'不显示' - ), - 'value'=>'1' - ) -); +return [ + ['name' => 'title', 'title' => '显示标题', 'type' => 'text', 'value' => 'SentCMS开发团队'], + ['name' => 'width', 'title' => '显示宽度', 'type' => 'select', 'value' => '6', 'option' => [ + ['key'=>'1', 'label'=>'1格'], + ['key'=>'2', 'label'=>'2格'], + ['key'=>'4', 'label'=>'4格'], + ['key'=>'6', 'label'=>'6格'] + ]], + ['name' => 'display', 'title' => '是否显示', 'type' => 'select', 'value' => '1', 'option' => [ + ['key'=>'1', 'label'=>'显示'], + ['key'=>'0', 'label'=>'不显示'] + ]], +]; \ No newline at end of file diff --git a/addons/sitestat/config.php b/addons/sitestat/config.php index 4c41ea42..ee5aa3b8 100644 --- a/addons/sitestat/config.php +++ b/addons/sitestat/config.php @@ -1,35 +1,21 @@ +// | Author: molong // +---------------------------------------------------------------------- -return array( - 'title'=>array(//配置在表单中的键名 ,这个会是config[title] - 'title'=>'显示标题:',//表单的文字 - 'type'=>'text', //表单的类型:text、textarea、checkbox、radio、select等 - 'value'=>'系统信息', //表单的默认值 - ), - 'width'=>array( - 'title'=>'显示宽度:', - 'type'=>'select', - 'options'=>array( - '4'=>'4格', - '6'=>'6格', - '12'=>'12格', - ), - 'value'=>'2' - ), - 'display'=>array( - 'title'=>'是否显示:', - 'type'=>'radio', - 'options'=>array( - '1'=>'显示', - '0'=>'不显示' - ), - 'value'=>'1' - ) -); +return [ + ['name' => 'title', 'title' => '显示标题', 'type' => 'text', 'value' => '系统信息'], + ['name' => 'width', 'title' => '显示宽度', 'type' => 'select', 'value' => '12', 'option' => [ + ['key'=>'4', 'label'=>'4格'], + ['key'=>'6', 'label'=>'6格'], + ['key'=>'12', 'label'=>'12格'] + ]], + ['name' => 'display', 'title' => '是否显示', 'type' => 'select', 'value' => '1', 'option' => [ + ['key'=>'1', 'label'=>'显示'], + ['key'=>'0', 'label'=>'不显示'] + ]], +]; \ No newline at end of file diff --git a/addons/systeminfo/config.php b/addons/systeminfo/config.php index fa5c7f57..ee2c0d34 100644 --- a/addons/systeminfo/config.php +++ b/addons/systeminfo/config.php @@ -1,35 +1,22 @@ +// | Author: molong // +---------------------------------------------------------------------- -return array( - 'title'=>array(//配置在表单中的键名 ,这个会是config[title] - 'title'=>'显示标题:',//表单的文字 - 'type'=>'text', //表单的类型:text、textarea、checkbox、radio、select等 - 'value'=>'系统信息', //表单的默认值 - ), - 'width'=>array( - 'title'=>'显示宽度:', - 'type'=>'select', - 'options'=>array( - '3'=>'3格', - '4'=>'4格', - '6'=>'6格' - ), - 'value'=>'6' - ), - 'display'=>array( - 'title'=>'是否显示:', - 'type'=>'radio', - 'options'=>array( - '1'=>'显示', - '0'=>'不显示' - ), - 'value'=>'1' - ) -); +return [ + ['name' => 'title', 'title' => '显示标题', 'type' => 'text', 'value' => '系统信息'], + ['name' => 'width', 'title' => '显示宽度', 'type' => 'select', 'value' => '6', 'option' => [ + ['key'=>'1', 'label'=>'1格'], + ['key'=>'2', 'label'=>'2格'], + ['key'=>'4', 'label'=>'4格'], + ['key'=>'6', 'label'=>'6格'] + ]], + ['name' => 'display', 'title' => '是否显示', 'type' => 'select', 'value' => '1', 'option' => [ + ['key'=>'1', 'label'=>'显示'], + ['key'=>'0', 'label'=>'不显示'] + ]], +]; \ No newline at end of file diff --git a/app/controller/Base.php b/app/controller/Base.php index 722f7de7..dafb0bfa 100644 --- a/app/controller/Base.php +++ b/app/controller/Base.php @@ -15,6 +15,7 @@ use think\facade\Cache; use think\Validate; use app\model\Config; use think\facade\Route; +use think\facade\Event; use app\model\Hooks; class Base { @@ -72,11 +73,26 @@ class Base { $config = Config::getConfigList($this->request); Cache::set('system_config_data', $config); } - $hooks = Hooks::where('status', 1)->column('addons', 'name'); - foreach($hooks as $key => $value){ - $hooks[$key] = $value ? explode(",", $value) : []; + $hooks = Cache::get('sentcms_hooks'); + if (!$hooks) { + $hooks = Hooks::where('status', 1)->column('addons', 'name'); + foreach($hooks as $key => $values){ + if (is_string($values)) { + $values = explode(',', $values); + } else { + $values = (array) $values; + } + $hooks[$key] = array_filter(array_map(function ($v) use ($key) { + return [get_addons_class($v), $key]; + }, $values)); + // $hooks[$key] = $value ? explode(",", $value) : []; + } } - Cache::set('sentcms_hooks', $hooks); + if (!empty($hooks)) { + Cache::set('sentcms_hooks', $hooks); + Event::listenEvents($hooks); + } + View::assign('config', $config); // 控制器初始化 $this->initialize(); diff --git a/app/controller/admin/Addons.php b/app/controller/admin/Addons.php index 2f3ae6cc..50e99006 100644 --- a/app/controller/admin/Addons.php +++ b/app/controller/admin/Addons.php @@ -10,6 +10,8 @@ namespace app\controller\admin; use app\model\Addons as AddonsM; use app\model\Hooks; +use think\facade\Cache; +use think\facade\Config; /** * @title 插件管理 @@ -50,26 +52,22 @@ class Addons extends Base { * @title 安装插件 */ public function install() { - $addon_name = input('addon_name', '', 'trim,ucfirst'); - $class = get_addon_class($addon_name); + $addon_name = input('addon_name', '', 'trim'); + $class = get_addons_class($addon_name); if (class_exists($class)) { - $addons = new $class; - $info = $addons->info; - if (!$info || !$addons->checkInfo()) { - //检测信息的正确性 - return $this->error('插件信息缺失'); - } + $addons = get_addons_instance($addon_name); + $info = $addons->getInfo(); session('addons_install_error', null); $install_flag = $addons->install(); if (!$install_flag) { return $this->error('执行插件预安装操作失败' . session('addons_install_error')); } - $result = $this->addons->install($info); + $result = AddonsM::install($info); if ($result) { - cache('hooks', null); + Cache::delete("sentcms_hooks"); return $this->success('安装成功'); } else { - return $this->error($this->addons->getError()); + return $this->error("安装失败!"); } } else { return $this->error('插件不存在'); @@ -80,8 +78,9 @@ class Addons extends Base { * @title 卸载插件 */ public function uninstall($id) { - $result = $this->addons->uninstall($id); + $result = AddonsM::uninstall($id); if ($result === false) { + Cache::delete("sentcms_hooks"); return $this->error($this->addons->getError(), ''); } else { return $this->success('卸载成功!'); @@ -91,12 +90,10 @@ class Addons extends Base { /** * @title 启用插件 */ - public function enable() { - $id = input('id'); - cache('hooks', null); - $model = model('Addons'); - $result = $model::where(array('id' => $id))->update(array('status' => 1)); + public function enable($id) { + $result = AddonsM::update(['status' => 1], ['id' => $id]); if ($result) { + Cache::delete('sentcms_hooks'); return $this->success('启用成功'); } else { return $this->error("启用失败!"); @@ -106,12 +103,10 @@ class Addons extends Base { /** * @title 禁用插件 */ - public function disable() { - $id = input('id'); - cache('hooks', null); - $model = model('Addons'); - $result = $model::where(array('id' => $id))->update(array('status' => 0)); + public function disable($id) { + $result = AddonsM::update(['status' => 0], ['id' => $id]); if ($result) { + Cache::delete('sentcms_hooks'); return $this->success('禁用成功'); } else { return $this->error("禁用失败!"); @@ -123,23 +118,30 @@ class Addons extends Base { */ public function config() { if ($this->request->isPost()) { - # code... + $config = $this->request->post(); + $id = $this->request->param('id'); + + $result = AddonsM::update(['config' => $config], ['id' => $id]); + if ($result) { + return $this->success('完成设置!'); + } else { + return $this->error("无法完成设置!"); + } } else { - $id = input('id', '', 'trim,intval'); + $id = $this->request->param('id'); if (!$id) { return $this->error("非法操作!"); } - $info = $this->addons->find($id); + $info = AddonsM::find($id); if (!empty($info)) { - $class = get_addon_class($info['name']); + $class = get_addons_instance($info['name']); - $keyList = array(); - $data = array( + $keyList = $class->getConfig(true); + $this->data = array( 'keyList' => $keyList, + 'meta_title' => $info['title'] . " - 设置" ); - $this->assign($data); - $this->setMeta($info['title'] . " - 设置"); - return $this->fetch('public/edit'); + return $this->fetch('admin/public/edit'); } else { return $this->error("未安装此插件!"); } @@ -222,7 +224,9 @@ class Addons extends Base { */ public function edithook($id) { if ($this->request->isPost()) { - $result = $hooks->change(); + $data = $this->request->post(); + + $result = Hooks::update($data, ['id' => $data['id']]); if ($result !== false) { return $this->success("修改成功"); } else { diff --git a/app/http/form/Factory.php b/app/http/form/Factory.php index 4e57e079..d86fe0b8 100644 --- a/app/http/form/Factory.php +++ b/app/http/form/Factory.php @@ -34,7 +34,7 @@ class Factory { } protected function parseValue(){ - $this->field['value'] = isset($this->data[$this->field['name']]) ? $this->data[$this->field['name']] : ''; + $this->field['value'] = isset($this->data[$this->field['name']]) ? $this->data[$this->field['name']] : (isset($this->field['value']) ? $this->field['value'] : ''); } public function show(){ diff --git a/app/model/Addons.php b/app/model/Addons.php index 415dab39..a8b2263e 100644 --- a/app/model/Addons.php +++ b/app/model/Addons.php @@ -18,7 +18,8 @@ class Addons extends \think\Model { protected $insert = ['create_time']; protected $type = [ - 'hooks' => 'json' + 'hooks' => 'json', + 'config' => 'json' ]; protected function setStatusAttr($value) { @@ -90,16 +91,15 @@ class Addons extends \think\Model { return $admin; } - public function install($data) { + public static function install($data) { if ($data) { - $info = $this->where('name', $data['name'])->value('id'); - if ($info) { - $result = $this->save(array('isinstall'=>1, 'status'=>1), array('id'=>$info)); - }else{ - $result = false; + $id = self::where('name', strtolower($data['name']))->value('id'); + $result = false; + if ($id) { + $result = self::update(['isinstall'=>1, 'status'=>1], ['id'=>$id]); } if (false !== $result) { - return model('Hooks')->addHooks($data['name']); + return Hooks::addHooks(strtolower($data['name'])); }else{ return false; } @@ -108,16 +108,16 @@ class Addons extends \think\Model { } } - public function uninstall($id) { - $info = $this->get($id); + public static function uninstall($id) { + $info = self::find($id); if (!$info) { $this->error = "无此插件!"; return false; } - $class = get_addon_class($info['name']); + $class = get_addons_class($info['name']); if (class_exists($class)) { //插件卸载方法 - $addons = new $class; + $addons = get_addons_instance($info['name']); if (!method_exists($addons, 'uninstall')) { $this->error = "插件卸载方法!"; return false; @@ -125,9 +125,9 @@ class Addons extends \think\Model { $result = $addons->uninstall(); if ($result) { //卸载挂载点中的插件 - $result = model('Hooks')->removeHooks($info['name']); + $result = Hooks::removeHooks($info['name']); //删除插件表中数据 - $this->where(array('id' => $id))->delete(); + $info->save(['isinstall' => 0]); return true; } else { $this->error = "无法卸载插件!"; diff --git a/app/model/Hooks.php b/app/model/Hooks.php index 9ed4ea67..ca22e35b 100644 --- a/app/model/Hooks.php +++ b/app/model/Hooks.php @@ -19,6 +19,12 @@ class Hooks extends \think\Model { return isset($type[$data['type']]) ? $type[$data['type']] : ''; } + protected function setAddonsAttr($value){ + if (!empty($value[0])) { + return implode(",", $value[0]); + } + } + public static function getaddons($addons){ if (isset($addons['addons']) && $addons['addons']) { $hook_list = explode(',', $addons['addons']); @@ -37,4 +43,45 @@ class Hooks extends \think\Model { ]; return $keylist; } + + public static function addHooks($name){ + // 读取插件目录及钩子列表 + $base = get_class_methods("\\sent\\Addons"); + // 读取出所有公共方法 + $methods = (array)get_class_methods("\\addons\\" . $name . "\\Plugin"); + // 跟插件基类方法做比对,得到差异结果 + $hooks = array_diff($methods, $base); + $row = self::where('name', 'IN', $hooks)->column("*", "name"); + $save = []; + foreach ($hooks as $value) { + if (isset($row[$value]) && !empty($row[$value])) { + $info = $row[$value]; + $addons = $info['addons'] ? explode(",", $info['addons']) : []; + empty($addons) ? [$name] : array_push($addons, $name); + $info['addons'] = implode(",", $addons); + $save[] = $info; + }else{ + $save[] = ['name' => $value, 'type' => 1, 'create_time' => time(), 'status' => 1, 'addons'=> $name]; + } + } + return (new self())->saveAll($save); + } + + public static function removeHooks($name){ + $row = self::where('addons', 'LIKE', '%'.$name.'%')->select()->toArray(); + $save = []; + foreach ($row as $value) { + $addons = explode(",", $value['addons']); + if (in_array($name, $addons)) { + array_splice($addons, array_search($name, $addons), 1); + } + $value['addons'] = !empty($addons) ? implode(",", $addons) : ""; + $save[] = $value; + } + if (!empty($save)) { + return (new self())->saveAll($save); + }else{ + return true; + } + } } \ No newline at end of file diff --git a/config/addons.php b/config/addons.php index b040d076..447bef2f 100644 --- a/config/addons.php +++ b/config/addons.php @@ -10,7 +10,7 @@ // +---------------------------------------------------------------------- return [ - 'autoload' => true, + 'autoload' => false, 'hooks' => [], 'route' => [], 'service' => [], diff --git a/public/static/common/css/hopscotch.css b/public/static/common/css/hopscotch.css deleted file mode 100644 index fb542a1f..00000000 --- a/public/static/common/css/hopscotch.css +++ /dev/null @@ -1 +0,0 @@ -.animated{-webkit-animation-fill-mode:both;-moz-animation-fill-mode:both;-ms-animation-fill-mode:both;-o-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:1s;-moz-animation-duration:1s;-ms-animation-duration:1s;-o-animation-duration:1s;animation-duration:1s;}@-webkit-keyframes fadeInUp{0%{opacity:0;-webkit-transform:translateY(20px);}100%{opacity:1;-webkit-transform:translateY(0);}}@-moz-keyframes fadeInUp{0%{opacity:0;-moz-transform:translateY(20px);}100%{opacity:1;-moz-transform:translateY(0);}}@-o-keyframes fadeInUp{0%{opacity:0;-o-transform:translateY(20px);}100%{opacity:1;-o-transform:translateY(0);}}@keyframes fadeInUp{0%{opacity:0;transform:translateY(20px);}100%{opacity:1;transform:translateY(0);}}.fade-in-up{-webkit-animation-name:fadeInUp;-moz-animation-name:fadeInUp;-o-animation-name:fadeInUp;animation-name:fadeInUp;}@-webkit-keyframes fadeInDown{0%{opacity:0;-webkit-transform:translateY(-20px);}100%{opacity:1;-webkit-transform:translateY(0);}}@-moz-keyframes fadeInDown{0%{opacity:0;-moz-transform:translateY(-20px);}100%{opacity:1;-moz-transform:translateY(0);}}@-o-keyframes fadeInDown{0%{opacity:0;-ms-transform:translateY(-20px);}100%{opacity:1;-ms-transform:translateY(0);}}@keyframes fadeInDown{0%{opacity:0;transform:translateY(-20px);}100%{opacity:1;transform:translateY(0);}}.fade-in-down{-webkit-animation-name:fadeInDown;-moz-animation-name:fadeInDown;-o-animation-name:fadeInDown;animation-name:fadeInDown;}@-webkit-keyframes fadeInRight{0%{opacity:0;-webkit-transform:translateX(-20px);}100%{opacity:1;-webkit-transform:translateX(0);}}@-moz-keyframes fadeInRight{0%{opacity:0;-moz-transform:translateX(-20px);}100%{opacity:1;-moz-transform:translateX(0);}}@-o-keyframes fadeInRight{0%{opacity:0;-o-transform:translateX(-20px);}100%{opacity:1;-o-transform:translateX(0);}}@keyframes fadeInRight{0%{opacity:0;transform:translateX(-20px);}100%{opacity:1;transform:translateX(0);}}.fade-in-right{-webkit-animation-name:fadeInRight;-moz-animation-name:fadeInRight;-o-animation-name:fadeInRight;animation-name:fadeInRight;}@-webkit-keyframes fadeInLeft{0%{opacity:0;-webkit-transform:translateX(20px);}100%{opacity:1;-webkit-transform:translateX(0);}}@-moz-keyframes fadeInLeft{0%{opacity:0;-moz-transform:translateX(20px);}100%{opacity:1;-moz-transform:translateX(0);}}@-o-keyframes fadeInLeft{0%{opacity:0;-o-transform:translateX(20px);}100%{opacity:1;-o-transform:translateX(0);}}@keyframes fadeInLeft{0%{opacity:0;transform:translateX(20px);}100%{opacity:1;transform:translateX(0);}}.fade-in-left{-webkit-animation-name:fadeInLeft;-moz-animation-name:fadeInLeft;-o-animation-name:fadeInLeft;animation-name:fadeInLeft;}div.hopscotch-bubble .hopscotch-nav-button{font-weight:bold;border-width:1px;border-style:solid;cursor:pointer;margin:0;overflow:visible;text-decoration:none!important;width:auto;padding:0 10px;height:26px;line-height:24px;font-size:12px;*zoom:1;white-space:nowrap;display:-moz-inline-stack;display:inline-block;*vertical-align:auto;zoom:1;*display:inline;vertical-align:middle;-moz-border-radius:3px;-ms-border-radius:3px;-o-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;}div.hopscotch-bubble .hopscotch-nav-button:hover{*zoom:1;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.25);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.25);box-shadow:0 1px 3px rgba(0,0,0,0.25);}div.hopscotch-bubble .hopscotch-nav-button:active{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.25) inset;-moz-box-shadow:0 1px 2px rgba(0,0,0,0.25) inset;box-shadow:0 1px 2px rgba(0,0,0,0.25) inset;}div.hopscotch-bubble .hopscotch-nav-button.next{border-color:#1b5480;color:#fff;margin:0 0 0 10px;text-shadow:0 1px 1px rgba(0,0,0,0.35);background-color:#287bbc;filter:progid:DXImageTransform.Microsoft.gradient(gradientType=0,startColorstr='#287bbc',endColorstr='#23639a');background-image:-webkit-gradient(linear,50% 0%,50% 100%,color-stop(0%,#287bbc),color-stop(100%,#23639a));background-image:-webkit-linear-gradient(top,#287bbc 0%,#23639a 100%);background-image:-moz-linear-gradient(top,#287bbc 0%,#23639a 100%);background-image:-o-linear-gradient(top,#287bbc 0%,#23639a 100%);background-image:linear-gradient(top,#287bbc 0%,#23639a 100%);}div.hopscotch-bubble .hopscotch-nav-button.next:hover{background-color:#2672ae;filter:progid:DXImageTransform.Microsoft.gradient(gradientType=0,startColorstr='#2672ae',endColorstr='#1e4f7e');background-image:-webkit-gradient(linear,50% 0%,50% 100%,color-stop(0%,#2672ae),color-stop(100%,#1e4f7e));background-image:-webkit-linear-gradient(top,#2672ae 0%,#1e4f7e 100%);background-image:-moz-linear-gradient(top,#2672ae 0%,#1e4f7e 100%);background-image:-o-linear-gradient(top,#2672ae 0%,#1e4f7e 100%);background-image:linear-gradient(top,#2672ae 0%,#1e4f7e 100%);}div.hopscotch-bubble .hopscotch-nav-button.prev{border-color:#a7a7a7;color:#444;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#f2f2f2;filter:progid:DXImageTransform.Microsoft.gradient(gradientType=0,startColorstr='#f2f2f2',endColorstr='#e9e9e9');background-image:-webkit-gradient(linear,50% 0%,50% 100%,color-stop(0%,#f2f2f2),color-stop(100%,#e9e9e9));background-image:-webkit-linear-gradient(top,#f2f2f2 0%,#e9e9e9 100%);background-image:-moz-linear-gradient(top,#f2f2f2 0%,#e9e9e9 100%);background-image:-o-linear-gradient(top,#f2f2f2 0%,#e9e9e9 100%);background-image:linear-gradient(top,#f2f2f2 0%,#e9e9e9 100%);}div.hopscotch-bubble .hopscotch-nav-button.prev:hover{background-color:#e8e8e8;filter:progid:DXImageTransform.Microsoft.gradient(gradientType=0,startColorstr='#FFE8E8E8',endColorstr='#FFA9A9A9');background-image:-webkit-gradient(linear,50% 0%,50% 100%,color-stop(0%,#e8e8e8),color-stop(13%,#e3e3e3),color-stop(32%,#d7d7d7),color-stop(71%,#b9b9b9),color-stop(100%,#a9a9a9));background-image:-webkit-linear-gradient(top,#e8e8e8 0%,#e3e3e3 13%,#d7d7d7 32%,#b9b9b9 71%,#a9a9a9 100%);background-image:-moz-linear-gradient(top,#e8e8e8 0%,#e3e3e3 13%,#d7d7d7 32%,#b9b9b9 71%,#a9a9a9 100%);background-image:-o-linear-gradient(top,#e8e8e8 0%,#e3e3e3 13%,#d7d7d7 32%,#b9b9b9 71%,#a9a9a9 100%);background-image:linear-gradient(top,#e8e8e8 0%,#e3e3e3 13%,#d7d7d7 32%,#b9b9b9 71%,#a9a9a9 100%);}div.hopscotch-bubble{background-color:#ffffff;border:5px solid #000000;border:5px solid rgba(0,0,0,0.5);border-radius:3px;font-size:13px;position:absolute;z-index:999999;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-moz-background-clip:padding;-webkit-background-clip:padding;background-clip:padding-box;}div.hopscotch-bubble *{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;}div.hopscotch-bubble.animate{-moz-transition-property:top,left;-moz-transition-duration:1s;-moz-transition-timing-function:ease-in-out;-ms-transition-property:top,left;-ms-transition-duration:1s;-ms-transition-timing-function:ease-in-out;-o-transition-property:top,left;-o-transition-duration:1s;-o-transition-timing-function:ease-in-out;-webkit-transition-property:top,left;-webkit-transition-duration:1s;-webkit-transition-timing-function:ease-in-out;transition-property:top,left;transition-duration:1s;transition-timing-function:ease-in-out;}div.hopscotch-bubble.invisible{opacity:0;}div.hopscotch-bubble.hide,div.hopscotch-bubble .hide,div.hopscotch-bubble .hide-all{display:none;}div.hopscotch-bubble h3{font-size:16px;font-weight:600;line-height:19px;margin:-1px 15px 0 0;padding:0;border:none;}div.hopscotch-bubble .hopscotch-bubble-container{padding:15px;position:relative;text-align:left;-webkit-font-smoothing:antialiased;}div.hopscotch-bubble .hopscotch-content{font-weight:normal;line-height:1.4;margin:-5px 0 11px;padding-top:8px;}div.hopscotch-bubble .hopscotch-bubble-content{margin:0 0 0 40px;}div.hopscotch-bubble.no-number .hopscotch-bubble-content{margin:0;}div.hopscotch-bubble .hopscotch-bubble-close{color:#000;display:block;height:8px;line-height:8px;padding:4px 7px;position:absolute;right:0;text-decoration:none;top:0;width:8px;}div.hopscotch-bubble .hopscotch-bubble-close:hover{color:#3498db;}div.hopscotch-bubble .hopscotch-bubble-close.hide,div.hopscotch-bubble .hopscotch-bubble-close.hide-all{display:none;}div.hopscotch-bubble .hopscotch-bubble-number{background:#2ecc71;color:#fff;display:block;float:left;font-size:17px;font-weight:bold;line-height:30px;padding:0;text-align:center;width:30px;height:30px;-moz-border-radius:50%;-webkit-border-radius:50%;border-radius:50%;}div.hopscotch-bubble .hopscotch-bubble-arrow-container{position:absolute;width:34px;height:34px;}div.hopscotch-bubble .hopscotch-bubble-arrow-container .hopscotch-bubble-arrow,div.hopscotch-bubble .hopscotch-bubble-arrow-container .hopscotch-bubble-arrow-border{width:0;height:0;}div.hopscotch-bubble .hopscotch-bubble-arrow-container.up{top:-22px;left:10px;}div.hopscotch-bubble .hopscotch-bubble-arrow-container.up .hopscotch-bubble-arrow{border-bottom:17px solid #ffffff;border-left:17px solid transparent;border-right:17px solid transparent;position:relative;top:-10px;}div.hopscotch-bubble .hopscotch-bubble-arrow-container.up .hopscotch-bubble-arrow-border{border-bottom:17px solid #000000;border-bottom:17px solid rgba(0,0,0,0.5);border-left:17px solid transparent;border-right:17px solid transparent;}div.hopscotch-bubble .hopscotch-bubble-arrow-container.down{bottom:-39px;left:10px;}div.hopscotch-bubble .hopscotch-bubble-arrow-container.down .hopscotch-bubble-arrow{border-top:17px solid #ffffff;border-left:17px solid transparent;border-right:17px solid transparent;position:relative;top:-24px;}div.hopscotch-bubble .hopscotch-bubble-arrow-container.down .hopscotch-bubble-arrow-border{border-top:17px solid #000000;border-top:17px solid rgba(0,0,0,0.5);border-left:17px solid transparent;border-right:17px solid transparent;}div.hopscotch-bubble .hopscotch-bubble-arrow-container.left{top:10px;left:-22px;}div.hopscotch-bubble .hopscotch-bubble-arrow-container.left .hopscotch-bubble-arrow{border-bottom:17px solid transparent;border-right:17px solid #ffffff;border-top:17px solid transparent;position:relative;left:7px;top:-34px;}div.hopscotch-bubble .hopscotch-bubble-arrow-container.left .hopscotch-bubble-arrow-border{border-right:17px solid #000000;border-right:17px solid rgba(0,0,0,0.5);border-bottom:17px solid transparent;border-top:17px solid transparent;}div.hopscotch-bubble .hopscotch-bubble-arrow-container.right{top:10px;right:-39px;}div.hopscotch-bubble .hopscotch-bubble-arrow-container.right .hopscotch-bubble-arrow{border-bottom:17px solid transparent;border-left:17px solid #ffffff;border-top:17px solid transparent;position:relative;left:-7px;top:-34px;}div.hopscotch-bubble .hopscotch-bubble-arrow-container.right .hopscotch-bubble-arrow-border{border-left:17px solid #000000;border-left:17px solid rgba(0,0,0,0.5);border-bottom:17px solid transparent;border-top:17px solid transparent;}div.hopscotch-bubble .hopscotch-actions{margin:10px 0 0;text-align:right;} \ No newline at end of file diff --git a/view/admin/form/lists.html b/view/admin/form/lists.html index ee72d883..3af1d215 100644 --- a/view/admin/form/lists.html +++ b/view/admin/form/lists.html @@ -35,7 +35,7 @@ {if isset($vo['format'])} {$item[$vo['field']]|$vo['format']} {else/} - {$item[$vo['field']]} + {$item[$vo['field']]|default=''} {/if} {/volist}