Title1

Title2

Title3

15. 圖示管理

一、結構規劃

  1. 資料表:creative_nav
  2. 關鍵字:icon_home
  3. 後台程式名稱:admin/icon.php
  4. 後台樣板:templates/admin/tpl/admin_icon.html

二、後台樣板

  1. templates/admin/theme.html
            <{if $WEB.file_name =="index.php"}>
              <{include file="tpl/admin_index.html"}>
            <{elseif $WEB.file_name =="icon.php"}>
              <{include file="tpl/admin_icon.html"}>
            <{/if}>

     

 

三、後台選單

  1. templates/admin/tpl/admin_nav.html
                <ul class="dropdown-menu dropdown-user">
                    <li><a href="index.php"><i class="fa fa-user fa-fw"></i> 選單管理</a>
                    </li>
                    <li><a href="icon.php"><i class="fa fa-gear fa-fw"></i> 圖示管理</a>
                    </li>
                    <li class="divider"></li>
                    <li><a href="../admin.php?op=op_logout"><i class="fa fa-sign-out fa-fw"></i> 登出</a>
                    </li>
                </ul>

     

四、fontawwsome iconpicker

  1. 官網:https://itsjavi.com/fontawesome-iconpicker/
  2. 安裝:
    參考網站:http://github.ugm.com.tw/soft/templates/op_form.html
    引入「font-awesome.min.css」
    引入「fontawesome-iconpicker.min.css」
    引入「fontawesome-iconpicker.min.js」
    調用插件
    更換jquery
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>


    程式碼 templates/admin/tpl/admin_icon.html
            <div class="row">          
              <link href="<{$themeUrl}>/vendor/font-awesome/css/font-awesome.min.css" rel="stylesheet">
              <link rel="stylesheet" type="text/css" href="<{$smarty.const.WEB_URL}>/class/fontawesome-iconpicker/css/fontawesome-iconpicker.min.css">
              <script type="text/javascript" src="<{$smarty.const.WEB_URL}>/class/fontawesome-iconpicker/js/fontawesome-iconpicker.min.js"></script>
              <script type='text/javascript'>
                $(document).ready(function(){
                  $('.icp').iconpicker();
                });
              </script>
              <div class="col-md-3">
                <div class="form-group">
                  <label>圖示</label>
                  <div class="input-group">
                    <input name="icon" id="icon" data-placement="bottomRight" class="form-control icp icp-auto" value="fa-archive" type="text" />
                    <span class="input-group-addon"></span>
                  </div>
                </div>      
              </div>
            </div>

     

五、多行表單

  1. 參考網站:http://github.ugm.com.tw/soft/templates/op_form.html
            
            <div class="row">
              <div class="col-md-12">
                <div class="form-group">
                  <label>摘要</label>
                  <textarea name="summary" id="summary" class="form-control" rows="3" placeholder="摘要"></textarea>
                </div>
              </div>          
            </div>

六、網頁編輯器 CKEDITOR

  1. 官網:http://ckeditor.com
  2. 下載Standard Package:http://ckeditor.com/download
  3. 將下載檔案解壓縮至 class/
  4. 引入js
  5. 調用插件
  6. 程式碼 templates/admin/tpl/admin_icon.html
            <div class="row">
              <script type="text/javascript" src="<{$smarty.const.WEB_URL}>/class/ckeditor/ckeditor.js"></script>
              <script>
                $(function() {
                  CKEDITOR.replace('content');
                });
              </script>
              <div class="col-md-12">
                <div class="form-group">
                  <label>內容</label>
                  <textarea name="content" id="content" class="form-control" rows="5" placeholder="內容"></textarea>
                </div>
              </div>          
            </div>

     

七、將elFinder整合至CKEDITOR

  1. 官網:https://studio-42.github.io/elFinder/
  2. 將下載檔案解壓縮至 class/elFinder
  3. 引入elFinder
              <script>
                $(function() {
                  CKEDITOR.replace('content', {
                    language : 'zh' ,
                    contentsCss : ['<{$themeUrl}>/vendor/bootstrap/css/bootstrap.min.css'],
                    filebrowserBrowseUrl : '<{$smarty.const.WEB_URL}>/class/elFinder/elfinder.html'
                  } );
                });
              </script>

     

  4. 修改 class/elFinder/elfinder.html
    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title>elFinder 2.1.x source version with PHP connector</title>
    		<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2" />
    
    		<!-- jQuery and jQuery UI (REQUIRED) -->
    		<link rel="stylesheet" type="text/css" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
    		<script src="//ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
    		<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
    
    		<!-- elFinder CSS (REQUIRED) -->
    		<link rel="stylesheet" type="text/css" href="css/elfinder.min.css">
    		<link rel="stylesheet" type="text/css" href="css/theme.css">
    
    		<!-- elFinder JS (REQUIRED) -->
    		<script src="js/elfinder.min.js"></script>
    
    		<!-- GoogleDocs Quicklook plugin for GoogleDrive Volume (OPTIONAL) -->
    		<!--<script src="js/extras/quicklook.googledocs.js"></script>-->
    
            <!-- elFinder translation (OPTIONAL) -->
            <script src="js/i18n/elfinder.zh_TW.js"></script>
    
            <!-- elFinder initialization (REQUIRED) -->
            <script type="text/javascript" charset="utf-8">
                // Helper function to get parameters from the query string.
                function getUrlParam(paramName) {
                    var reParam = new RegExp('(?:[\?&]|&amp;)' + paramName + '=([^&]+)', 'i') ;
                    var match = window.location.search.match(reParam) ;
    
                    return (match && match.length > 1) ? match[1] : '' ;
                }
    
                $().ready(function() {
                    var funcNum = getUrlParam('CKEditorFuncNum');
    
                    var elf = $('#elfinder').elfinder({
                        url : 'php/connector.minimal.php',
                        lang: 'zh_TW',                    // language (OPTIONAL)
                        getFileCallback : function(file) {
                            window.opener.CKEDITOR.tools.callFunction(funcNum, file.url);
                            window.close();
                        },
                        resizable: false
                    }).elfinder('instance');
                });
            </script>
    	</head>
    	<body>
    
    		<!-- Element where elFinder will be created (REQUIRED) -->
    		<div id="elfinder"></div>
    
    	</body>
    </html>
    

     

  5. 修改 class/elFinder/php/connector.minimal.php
    <?php
    
    error_reporting(0); // Set E_ALL for debuging
    
    include_once "../../../head.php";
    include_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'elFinderConnector.class.php';
    include_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'elFinder.class.php';
    include_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'elFinderVolumeDriver.class.php';
    include_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'elFinderVolumeLocalFileSystem.class.php';
    // Required for MySQL storage connector
    // include_once dirname(__FILE__).DIRECTORY_SEPARATOR.'elFinderVolumeMySQL.class.php';
    // Required for FTP connector support
    // include_once dirname(__FILE__).DIRECTORY_SEPARATOR.'elFinderVolumeFTP.class.php';
    // ===============================================
    
    /**
     * # Dropbox volume driver need `composer require dropbox-php/dropbox-php:dev-master@dev`
     *  OR "dropbox-php's Dropbox" and "PHP OAuth extension" or "PEAR's HTTP_OAUTH package"
     * * dropbox-php: http://www.dropbox-php.com/
     * * PHP OAuth extension: http://pecl.php.net/package/oauth
     * * PEAR's HTTP_OAUTH package: http://pear.php.net/package/http_oauth
     *  * HTTP_OAUTH package require HTTP_Request2 and Net_URL2
     */
    // // Required for Dropbox.com connector support
    // // On composer
    // require 'vendor/autoload.php';
    // elFinder::$netDrivers['dropbox'] = 'Dropbox';
    // // OR on pear
    // include_once dirname(__FILE__).DIRECTORY_SEPARATOR.'elFinderVolumeDropbox.class.php';
    
    // // Dropbox driver need next two settings. You can get at https://www.dropbox.com/developers
    // define('ELFINDER_DROPBOX_CONSUMERKEY',    '');
    // define('ELFINDER_DROPBOX_CONSUMERSECRET', '');
    // define('ELFINDER_DROPBOX_META_CACHE_PATH',''); // optional for `options['metaCachePath']`
    // ===============================================
    
    // // Required for Google Drive network mount
    // // Installation by composer
    // // `composer require nao-pon/flysystem-google-drive:~1.1 google/apiclient:~2.0@rc nao-pon/elfinder-flysystem-driver-ext`
    // // composer autoload
    // require 'vendor/autoload.php';
    // // Enable network mount
    // elFinder::$netDrivers['googledrive'] = 'FlysystemGoogleDriveNetmount';
    // // GoogleDrive Netmount driver need next two settings. You can get at https://console.developers.google.com
    // // AND reuire regist redirect url to "YOUR_CONNECTOR_URL?cmd=netmount&protocol=googledrive&host=1"
    // define('ELFINDER_GOOGLEDRIVE_CLIENTID',     '');
    // define('ELFINDER_GOOGLEDRIVE_CLIENTSECRET', '');
    // ===============================================
    
    /**
     * Simple function to demonstrate how to control file access using "accessControl" callback.
     * This method will disable accessing files/folders starting from '.' (dot)
     *
     * @param  string  $attr  attribute name (read|write|locked|hidden)
     * @param  string  $path  file path relative to volume root directory started with directory separator
     * @return bool|null
     **/
    function access($attr, $path, $data, $volume) {
    	return strpos(basename($path), '.') === 0// if file/folder begins with '.' (dot)
    	 ? !($attr == 'read' || $attr == 'write') // set read+write to false, other (locked+hidden) set to true
    	 : null; // else elFinder decide it itself
    }
    
    // Documentation for connector options:
    // https://github.com/Studio-42/elFinder/wiki/Connector-configuration-options
    $opts = array(
    	// 'debug' => true,
    	'roots' => array(
    		array(
    			'driver' => 'LocalFileSystem', // driver for accessing file system (REQUIRED)
    			'path' => WEB_PATH . "/uploads/", // path to files (REQUIRED)
    			'URL' => WEB_URL . "/uploads/", // URL to files (REQUIRED)
    			'uploadDeny' => array('all'), // All Mimetypes not allowed to upload
    			'uploadAllow' => array('image', 'text/plain'), // Mimetype `image` and `text/plain` allowed to upload
    			'uploadOrder' => array('deny', 'allow'), // allowed Mimetype `image` and `text/plain` only
    			'accessControl' => 'access', // disable and hide dot starting files (OPTIONAL)
    		),
    	),
    );
    
    // run elFinder
    $connector = new elFinderConnector(new elFinder($opts));
    $connector->run();
    

     

八、op_insert
 

參考:http://php.net/manual/en/function.json-encode.php

#################################
# 新增資料
#
#################################
function op_insert() {
	global $mysqli;
	//print_r($_POST);die();

	#資料過濾
	#http://php.net/manual/en/mysqli.real-escape-string.php
	$_POST['title'] = $mysqli->real_escape_string($_POST['title']);
	$_POST['target'] = intval($_POST['target']);
	$_POST['enable'] = intval($_POST['enable']);
	$_POST['sort'] = intval($_POST['sort']);
	$_POST['url'] = $mysqli->real_escape_string($_POST['url']);
	$_POST['kind'] = $mysqli->real_escape_string($_POST['kind']);

	#圖示、摘要與內容存成json
	$content['icon'] = $mysqli->real_escape_string($_POST['icon']);
	$content['summary'] = $mysqli->real_escape_string($_POST['summary']);
	$content['content'] = $mysqli->real_escape_string($_POST['content']);
	$_POST['content'] = json_encode($content, JSON_NUMERIC_CHECK | JSON_UNESCAPED_UNICODE);

	$sql = "insert into `creative_nav`
          (`title`, `target`, `enable`, `sort`,`url`,`kind`,`content`)
          VALUES
          ('{$_POST['title']}', '{$_POST['target']}', '{$_POST['enable']}', '{$_POST['sort']}', '{$_POST['url']}', '{$_POST['kind']}', '{$_POST['content']}')"; //die($sql);

	$mysqli->query($sql) or die(printf("Error: %s <br>" . $sql, $mysqli->sqlstate));

	$sn = $mysqli->insert_id; //傳回insert 指令所產生之流水號

	return $sn;
}


九、op_update
 

#################################
# 更新資料
#
#################################
function op_update($sn = "") {
	global $mysqli;
	if (!$sn) {
		redirect_header("index.php", 3000, "更新記錄錯誤!!");
	}

	#資料過濾
	$_POST['sn'] = intval($_POST['sn']);
	$_POST['title'] = $mysqli->real_escape_string($_POST['title']);
	$_POST['target'] = intval($_POST['target']);
	$_POST['enable'] = intval($_POST['enable']);
	$_POST['sort'] = intval($_POST['sort']);
	$_POST['url'] = $mysqli->real_escape_string($_POST['url']);

	#圖示、摘要與內容存成json
	$content['icon'] = $mysqli->real_escape_string($_POST['icon']);
	$content['summary'] = $mysqli->real_escape_string($_POST['summary']);
	$content['content'] = $mysqli->real_escape_string($_POST['content']);
	$_POST['content'] = json_encode($content, JSON_NUMERIC_CHECK | JSON_UNESCAPED_UNICODE);

	$sql = "update `creative_nav` set
          `title`  = '{$_POST['title']}' ,
          `target` = '{$_POST['target']}',
          `enable` = '{$_POST['enable']}',
          `url` = '{$_POST['url']}',
          `sort` = '{$_POST['sort']}',
          `content` = '{$_POST['content']}'
          where sn='{$_POST['sn']}'";

	$mysqli->query($sql) or die(printf("Error: %s <br>" . $sql, $mysqli->sqlstate));

	return $sn;
}

十、撈出單筆資料

  1. get_creative_nav
    ########################################
    #取得單筆記錄
    ########################################
    function get_creative_nav($sn = "") {
      global $mysqli;
      if (!$sn) {
        redirect_header("index.php", 3000, "查詢選單資料錯誤!!");
      }
     
      $sql = "select *
              from `creative_nav`
              where `sn`='{$sn}' and `kind`= 'icon_home'";
      $result = $mysqli->query($sql) or die(printf("Error: %s <br>" . $sql, $mysqli->sqlstate));
      $row = $result->fetch_assoc();
     
      #過濾撈出資料
      $row['sn'] = intval($row['sn']);
      //http://www.w3school.com.cn/php/func_string_htmlspecialchars.asp
      $row['title'] = htmlspecialchars($row['title'], ENT_QUOTES); // 轉換雙引號和單引號
      $row['url'] = htmlspecialchars($row['url'], ENT_QUOTES); // 轉換雙引號和單引號
      $row['sort'] = intval($row['sort']);
      $row['enable'] = intval($row['enable']);
      $row['target'] = intval($row['target']);
    
    
      $content = json_decode($row['content'], true); //(PHP 5 >= 5.2.0 true=>array 
      
      $row['icon'] = htmlspecialchars($content['icon'], ENT_QUOTES); // 轉換雙引號和單引號
      $row['summary'] = htmlspecialchars($content['summary'], ENT_QUOTES); // 轉換雙引號和單引號
      $row['content'] = htmlspecialchars($content['content'], ENT_QUOTES); // 轉換雙引號和單引號
    
     
      return $row;
    }

     

 

十一、op_form

參考:http://php.net/manual/en/function.json-decode.php

#################################
# 表單
# 選單關鍵字 icon_home
#################################
function op_form($sn = "") {
  global $mysqli, $smarty;
 
  #取得預設值
  if ($sn) {
    #編輯
    $row = get_creative_nav($sn); //取得單筆記錄
    $row['op'] = "op_update";
    $row['form_title'] = "編輯選單";
  } else {
    #新增
    $row = array();
    $row['op'] = "op_insert";
    $row['form_title'] = "新增選單";
  }
 
  #預設值設定
  $row['sn'] = (isset($row['sn'])) ? $row['sn'] : "";
  $row['title'] = (isset($row['title'])) ? $row['title'] : "";
  $row['enable'] = (isset($row['enable'])) ? $row['enable'] : 1;
  $row['target'] = (isset($row['target'])) ? $row['target'] : 0;
  $row['url'] = (isset($row['url'])) ? $row['url'] : "";
  $row['sort'] = (isset($row['sort'])) ? $row['sort'] : 0;
  $row['kind'] = (isset($row['kind'])) ? $row['kind'] : "icon_home";

  $row['icon'] = (isset($row['icon'])) ? $row['icon'] : "fa-android";
  $row['content'] = (isset($row['content'])) ? $row['content'] : "";
  $row['summary'] = (isset($row['summary'])) ? $row['summary'] : "";

 
  #把變數送至樣板
  $smarty->assign("row", $row);
}

十二、修改樣板

  1. 用「新聞」取代「選單」在 icon.php 與 templates/admin/tpl/admin_icon.html
  2. 「textarea」預設值
    
              <div class="col-md-12">
                <div class="form-group">
                  <label>內容</label>
                  <textarea name="content" id="content" class="form-control" rows="5" placeholder="內容"><{$row.content}></textarea>
                </div>
              </div>