Merge pull request #469 from anaqreon/website-import

Website import tool
This commit is contained in:
hubzilla 2016-08-01 09:13:43 +10:00 committed by GitHub
commit 74c68f09e5
15 changed files with 877 additions and 1 deletions

View File

@ -45,7 +45,29 @@ class Webpages extends \Zotlabs\Web\Controller {
$observer = \App::get_observer();
$channel = \App::get_channel();
switch ($_SESSION['action']) {
case 'import':
$_SESSION['action'] = null;
$o .= replace_macros(get_markup_template('webpage_import.tpl'), array(
'$title' => t('Import Webpage Elements'),
'$importbtn' => t('Import selected'),
'$action' => 'import',
'$pages' => $_SESSION['pages'],
'$layouts' => $_SESSION['layouts'],
'$blocks' => $_SESSION['blocks'],
));
return $o;
case 'importselected':
$_SESSION['action'] = null;
break;
default :
$_SESSION['action'] = null;
break;
}
if(\App::$is_sys && is_site_admin()) {
$sys = get_sys_channel();
if($sys && intval($sys['channel_id'])) {
@ -209,4 +231,165 @@ class Webpages extends \Zotlabs\Web\Controller {
return $o;
}
function post() {
$action = $_REQUEST['action'];
if( $action ){
switch ($action) {
case 'scan':
// the state of this variable tracks whether website files have been scanned (null, true, false)
$cloud = null;
// Website files are to be imported from an uploaded zip file
if(($_FILES) && array_key_exists('zip_file',$_FILES) && isset($_POST['w_upload'])) {
$source = $_FILES["zip_file"]["tmp_name"];
$type = $_FILES["zip_file"]["type"];
$okay = false;
$accepted_types = array('application/zip', 'application/x-zip-compressed', 'multipart/x-zip', 'application/x-compressed');
foreach ($accepted_types as $mime_type) {
if ($mime_type == $type) {
$okay = true;
break;
}
}
if(!$okay) {
notice( t('Invalid file type.') . EOL);
return;
}
$zip = new \ZipArchive();
if ($zip->open($source) === true) {
$tmp_folder_name = random_string(5);
$website = dirname($source) . '/' . $tmp_folder_name;
$zip->extractTo($website); // change this to the correct site path
$zip->close();
@unlink($source); // delete the compressed file now that the content has been extracted
$cloud = false;
} else {
notice( t('Error opening zip file') . EOL);
return null;
}
}
// Website files are to be imported from the channel cloud files
if (($_POST) && array_key_exists('path',$_POST) && isset($_POST['cloudsubmit'])) {
$channel = \App::get_channel();
$dirpath = get_dirpath_by_cloudpath($channel, $_POST['path']);
if(!$dirpath) {
notice( t('Invalid folder path.') . EOL);
return null;
}
$cloud = true;
}
// If the website files were uploaded or specified in the cloud files, then $cloud
// should be either true or false
if ($cloud !== null) {
require_once('include/import.php');
$elements = [];
if($cloud) {
$path = $_POST['path'];
} else {
$path = $website;
}
$elements['pages'] = scan_webpage_elements($path, 'page', $cloud);
$elements['layouts'] = scan_webpage_elements($path, 'layout', $cloud);
$elements['blocks'] = scan_webpage_elements($path, 'block', $cloud);
$_SESSION['blocks'] = $elements['blocks'];
$_SESSION['layouts'] = $elements['layouts'];
$_SESSION['pages'] = $elements['pages'];
if(!(empty($elements['pages']) && empty($elements['blocks']) && empty($elements['layouts']))) {
//info( t('Webpages elements detected.') . EOL);
$_SESSION['action'] = 'import';
} else {
notice( t('No webpage elements detected.') . EOL);
$_SESSION['action'] = null;
}
}
// If the website elements were imported from a zip file, delete the temporary decompressed files
if ($cloud === false && $website && $elements) {
rrmdir($website); // Delete the temporary decompressed files
}
break;
case 'importselected':
require_once('include/import.php');
$channel = \App::get_channel();
// Import layout first so that pages that reference new layouts will find
// the mid of layout items in the database
// Obtain the user-selected layouts to import and import them
$checkedlayouts = $_POST['layout'];
$layouts = [];
if (!empty($checkedlayouts)) {
foreach ($checkedlayouts as $name) {
foreach ($_SESSION['layouts'] as &$layout) {
if ($layout['name'] === $name) {
$layout['import'] = 1;
$layoutstoimport[] = $layout;
}
}
}
foreach ($layoutstoimport as $elementtoimport) {
$layouts[] = import_webpage_element($elementtoimport, $channel, 'layout');
}
}
$_SESSION['import_layouts'] = $layouts;
// Obtain the user-selected blocks to import and import them
$checkedblocks = $_POST['block'];
$blocks = [];
if (!empty($checkedblocks)) {
foreach ($checkedblocks as $name) {
foreach ($_SESSION['blocks'] as &$block) {
if ($block['name'] === $name) {
$block['import'] = 1;
$blockstoimport[] = $block;
}
}
}
foreach ($blockstoimport as $elementtoimport) {
$blocks[] = import_webpage_element($elementtoimport, $channel, 'block');
}
}
$_SESSION['import_blocks'] = $blocks;
// Obtain the user-selected pages to import and import them
$checkedpages = $_POST['page'];
$pages = [];
if (!empty($checkedpages)) {
foreach ($checkedpages as $pagelink) {
foreach ($_SESSION['pages'] as &$page) {
if ($page['pagelink'] === $pagelink) {
$page['import'] = 1;
$pagestoimport[] = $page;
}
}
}
foreach ($pagestoimport as $elementtoimport) {
$pages[] = import_webpage_element($elementtoimport, $channel, 'page');
}
}
$_SESSION['import_pages'] = $pages;
if(!(empty($_SESSION['import_pages']) && empty($_SESSION['import_blocks']) && empty($_SESSION['import_layouts']))) {
info( t('Import complete.') . EOL);
}
break;
default :
break;
}
}
}
}

View File

@ -371,6 +371,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
);
if ($r) {
require_once('include/attach.php');
$result = attach_mkdir($r[0], $this->auth->observer, array('filename' => $name, 'folder' => $this->folder_hash));
if($result['success']) {

View File

@ -0,0 +1,8 @@
<dl class="dl-horizontal">
<dt>General</dt>
<dd>You can create modular, identity-aware websites composed of shareable elements. </dd>
<dt>Pages</dt>
<dd>This page lists your "pages", which are assigned URLs where people can visit your site. The structure of pages are typically described by an associated <b>layout</b>, and their content is constructed from a collection of <b>blocks</b>.</dd>
<dt><a href='#' onclick='contextualHelpFocus("#website-import-tools", 1); return false;' title="Click to highlight element...">Website import tool</a></dt>
<dd>The website import tool allows you import multiple webpage elements (pages, layouts, blocks) either from an uploaded zip file or from an existing cloud files folder. <a target="_blank" href="help/webpages">Read more...</a></dd>
</dl>

View File

@ -0,0 +1,94 @@
## <a href="#webpage-element-import"></a>Webpage element import
There are two methods of importing webpage elements: uploading a zip file or
referencing a local cloud files folder. Both methods require that the webpage
elements are specified using a specific folder structure. The import tool makes
it possible to import all the elements necessary to construct an entire website
or set of websites. The goal is to accommodate external development of webpages
as well as tools to simplify and automate deployment on a hub.
### Folder structure
Element definitions must be stored in the repo root under folders called
/pages/
/blocks/
/layouts/
Each element of these types must be defined in an individual subfolder using two files: one JSON-formatted file for the metadata and one plain text file for the element content.
### Page elements
Page element metadata is specified in a JSON-formatted file called `page.json` with the following properties:
* title
* pagelink
* mimetype
* layout
* contentfile
**Example**
Files:
/pages/my-page/page.json
/pages/my-page/my-page.bbcode
Content of `page.json`:
{
"title": "My Page",
"pagelink": "mypage",
"mimetype": "text/bbcode",
"layout": "my-layout",
"contentfile": "my-page.bbcode"
}
### Layout elements
Layout element metadata is specified in a JSON-formatted file called `layout.json` with the following properties:
* name
* description
* contentfile
**Example**
Files:
/layouts/my-layout/layout.json
/layouts/my-layout/my-layout.bbcode
Content of `layout.json`:
{
"name": "my-layout",
"description": "Layout for my project page",
"contentfile": "my-layout.bbcode"
}
### Block elements
Block element metadata is specified in a JSON-formatted file called `block.json` with the following properties:
* name
* title
* mimetype
* contentfile
**Example**
Files:
/blocks/my-block/block.json
/blocks/my-block/my-block.html
Content of `block.json`:
{
"name": "my-block",
"title": "",
"mimetype": "text/html",
"contentfile": "my-block.html"
}

View File

@ -9,6 +9,9 @@ The &quot;page link title&quot; box allows a user to specify the &quot;pagelinkt
Beneath the page creation box, a list of existing pages will appear with an &quot;edit&quot; link. Clicking this will take you to an editor, similar to that of the post editor, where you can make changes to your webpages.
See also:
[zrl=[baseurl]/help/webpage-element-import]Webpage element import tool[/zrl]
[b]Using Blocks[/b]

View File

@ -13,4 +13,5 @@ Beneath the page creation box, a list of existing pages will appear with an "edi
If you are the admin of a site, you can specify a channel whose webpages we will use at key points around the site. Presently, the only place this is implemented is the home page. If you specify the channel "admin" and then the channel called "admin" creates a webpage called "home", we will display it's content on your websites home page. We expect this functionality to be extended to other areas in future.
#include doc/webpage-element-import.md;
#include doc/macros/main_footer.bb;

View File

@ -1911,3 +1911,70 @@ function get_attach_binname($s) {
}
return $p;
}
function get_dirpath_by_cloudpath($channel, $path) {
// Warning: Do not edit the following line. The first symbol is UTF-8 &#65312;
$path = str_replace('@','@',notags(trim($path)));
$h = @parse_url($path);
if(! $h || !x($h, 'path')) {
return null;
}
if(substr($h['path'],-1,1) === '/') {
$h['path'] = substr($h['path'],0,-1);
}
if(substr($h['path'],0,1) === '/') {
$h['path'] = substr($h['path'],1);
}
$folders = explode('/', $h['path']);
$f = array_shift($folders);
$nick = $channel['channel_address'];
//check to see if the absolute path was provided (/cloud/channelname/path/to/folder)
if($f === 'cloud' ) {
$g = array_shift($folders);
if( $g !== $nick) {
// if nick does not follow "cloud", then the top level folder must be called "cloud"
// and the given path must be relative to "/cloud/channelname/".
$folders = array_unshift(array_unshift($folders, $g), $f);
}
} else {
array_unshift($folders, $f);
}
$clouddir = 'store/' . $nick . '/' ;
$subdir = '/';
$valid = true;
while($folders && $valid && is_dir($clouddir . $subdir) && is_readable($clouddir . $subdir)) {
$valid = false;
$f = array_shift($folders);
$items = array_diff(scandir($clouddir . $subdir), array('.', '..')); // hashed names
foreach($items as $item) {
$filename = find_filename_by_hash($channel['channel_id'], $item);
if($filename === $f) {
$subdir .= $item . '/';
$valid = true;
}
}
}
if(!$valid) {
return null;
} else {
return $clouddir . $subdir;
}
}
function get_filename_by_cloudname($cloudname, $channel, $storepath) {
$items = array_diff(scandir($storepath), array('.', '..')); // hashed names
foreach($items as $item) {
$filename = find_filename_by_hash($channel['channel_id'], $item);
if($filename === $cloudname) {
return $item;
}
}
return null;
}

View File

@ -1246,3 +1246,216 @@ function convert_oldfields(&$arr,$old,$new) {
unset($arr[$old]);
}
}
function scan_webpage_elements($path, $type, $cloud = false) {
$channel = \App::get_channel();
$dirtoscan = $path;
switch ($type) {
case 'page':
$dirtoscan .= '/pages/';
$json_filename = 'page.json';
break;
case 'layout':
$dirtoscan .= '/layouts/';
$json_filename = 'layout.json';
break;
case 'block':
$dirtoscan .= '/blocks/';
$json_filename = 'block.json';
break;
default :
return array();
}
if($cloud) {
$dirtoscan = get_dirpath_by_cloudpath($channel, $dirtoscan);
}
$elements = [];
if (is_dir($dirtoscan)) {
$dirlist = scandir($dirtoscan);
if ($dirlist) {
foreach ($dirlist as $element) {
if ($element === '.' || $element === '..') {
continue;
}
$folder = $dirtoscan . '/' . $element;
if (is_dir($folder)) {
if($cloud) {
$jsonfilepath = $folder . '/' . get_filename_by_cloudname($json_filename, $channel, $folder);
} else {
$jsonfilepath = $folder . '/' . $json_filename;
}
if (is_file($jsonfilepath)) {
$metadata = json_decode(file_get_contents($jsonfilepath), true);
if($cloud) {
$contentfilename = get_filename_by_cloudname($metadata['contentfile'], $channel, $folder);
$metadata['path'] = $folder . '/' . $contentfilename;
} else {
$contentfilename = $metadata['contentfile'];
$metadata['path'] = $folder . '/' . $contentfilename;
}
if ($metadata['contentfile'] === '') {
logger('Invalid ' . $type . ' content file');
return false;
}
$content = file_get_contents($folder . '/' . $contentfilename);
if (!$content) {
logger('Failed to get file content for ' . $metadata['contentfile']);
return false;
}
$elements[] = $metadata;
}
}
}
}
}
return $elements;
}
function import_webpage_element($element, $channel, $type) {
$arr = array(); // construct information for the webpage element item table record
switch ($type) {
//
// PAGES
//
case 'page':
$arr['item_type'] = ITEM_TYPE_WEBPAGE;
$namespace = 'WEBPAGE';
$name = $element['pagelink'];
if($name) {
require_once('library/urlify/URLify.php');
$name = strtolower(\URLify::transliterate($name));
}
$arr['title'] = $element['title'];
$arr['term'] = $element['term'];
$arr['layout_mid'] = ''; // by default there is no layout associated with the page
// If a layout was specified, find it in the database and get its info. If
// it does not exist, leave layout_mid empty
if($element['layout'] !== '') {
$liid = q("select iid from iconfig where k = 'PDL' and v = '%s' and cat = 'system'",
dbesc($element['layout'])
);
if($liid) {
$linfo = q("select mid from item where id = %d",
intval($liid[0]['iid'])
);
$arr['layout_mid'] = $linfo[0]['mid'];
}
}
break;
//
// LAYOUTS
//
case 'layout':
$arr['item_type'] = ITEM_TYPE_PDL;
$namespace = 'PDL';
$name = $element['name'];
$arr['title'] = $element['description'];
$arr['term'] = $element['term'];
break;
//
// BLOCKS
//
case 'block':
$arr['item_type'] = ITEM_TYPE_BLOCK;
$namespace = 'BUILDBLOCK';
$name = $element['name'];
$arr['title'] = $element['title'];
break;
default :
return null; // return null if invalid element type
}
$arr['uid'] = $channel['channel_id'];
$arr['aid'] = $channel['channel_account_id'];
// Check if an item already exists based on the name
$iid = q("select iid from iconfig where k = '" . $namespace . "' and v = '%s' and cat = 'system'",
dbesc($name)
);
if($iid) { // If the item does exist, get the item metadata
$iteminfo = q("select mid,created,edited from item where id = %d",
intval($iid[0]['iid'])
);
$arr['mid'] = $arr['parent_mid'] = $iteminfo[0]['mid'];
$arr['created'] = $iteminfo[0]['created'];
$arr['edited'] = (($element['edited']) ? datetime_convert('UTC', 'UTC', $element['edited']) : datetime_convert());
} else { // otherwise, generate the creation times and unique id
$arr['created'] = (($element['created']) ? datetime_convert('UTC', 'UTC', $element['created']) : datetime_convert());
$arr['edited'] = datetime_convert('UTC', 'UTC', '0000-00-00 00:00:00');
$arr['mid'] = $arr['parent_mid'] = item_message_id();
}
// Import the actual element content
$arr['body'] = file_get_contents($element['path']);
// The element owner is the channel importing the elements
$arr['owner_xchan'] = get_observer_hash();
// The author is either the owner or whomever was specified
$arr['author_xchan'] = (($element['author_xchan']) ? $element['author_xchan'] : get_observer_hash());
// Import mimetype if it is a valid mimetype for the element
$mimetypes = [ 'text/bbcode',
'text/html',
'text/markdown',
'text/plain',
'application/x-pdl',
'application/x-php'
];
// Blocks and pages can have any mimetype, but layouts must be text/bbcode
if((in_array($element['mimetype'], $mimetypes)) && ($type === 'page' || $type === 'block') ) {
$arr['mimetype'] = $element['mimetype'];
} else {
$arr['mimetype'] = 'text/bbcode';
}
// Verify ability to use html or php!!!
$execflag = false;
if ($arr['mimetype'] === 'application/x-php') {
$z = q("select account_id, account_roles, channel_pageflags from account "
. "left join channel on channel_account_id = account_id where channel_id = %d limit 1",
intval(local_channel())
);
if ($z && (($z[0]['account_roles'] & ACCOUNT_ROLE_ALLOWCODE) || ($z[0]['channel_pageflags'] & PAGE_ALLOWCODE))) {
$execflag = true;
}
}
$z = q("select * from iconfig where v = '%s' and k = '%s' and cat = 'service' limit 1",
dbesc($name),
dbesc($namespace)
);
$i = q("select id, edited, item_deleted from item where mid = '%s' and uid = %d limit 1",
dbesc($arr['mid']),
intval(local_channel())
);
$remote_id = 0;
if ($z && $i) {
$remote_id = $z[0]['id'];
$arr['id'] = $i[0]['id'];
// don't update if it has the same timestamp as the original
if ($arr['edited'] > $i[0]['edited'])
$x = item_store_update($arr, $execflag);
} else {
if (($i) && (intval($i[0]['item_deleted']))) {
// was partially deleted already, finish it off
q("delete from item where mid = '%s' and uid = %d",
dbesc($arr['mid']),
intval(local_channel())
);
}
$x = item_store($arr, $execflag);
}
if ($x['success']) {
$item_id = $x['item_id'];
update_remote_id($channel, $item_id, $arr['item_type'], $name, $namespace, $remote_id, $arr['mid']);
$element['import_success'] = 1;
} else {
$element['import_success'] = 0;
}
return $element;
}

View File

@ -2242,6 +2242,34 @@ function design_tools() {
));
}
/**
* @brief Creates website import tools menu
*
* @return string
*/
function website_import_tools() {
$channel = App::get_channel();
$sys = false;
if(App::$is_sys && is_site_admin()) {
require_once('include/channel.php');
$channel = get_sys_channel();
$sys = true;
}
return replace_macros(get_markup_template('website_import_tools.tpl'), array(
'$title' => t('Import'),
'$import_label' => t('Import website...'),
'$import_placeholder' => t('Select folder to import'),
'$file_upload_text' => t('Import from a zipped folder:'),
'$file_import_text' => t('Import from cloud files:'),
'$desc' => t('/cloud/channel/path/to/folder'),
'$hint' => t('Enter path to website files'),
'$select' => t('Select folder'),
));
}
/* case insensitive in_array() */
function in_arrayi($needle, $haystack) {

View File

@ -779,6 +779,20 @@ function widget_design_tools($arr) {
return design_tools();
}
function widget_website_import_tools($arr) {
// mod menu doesn't load a profile. For any modules which load a profile, check it.
// otherwise local_channel() is sufficient for permissions.
if(App::$profile['profile_uid'])
if((App::$profile['profile_uid'] != local_channel()) && (! App::$is_sys))
return '';
if(! local_channel())
return '';
return website_import_tools();
}
function widget_findpeople($arr) {
return findpeople_widget();

View File

@ -34,3 +34,88 @@
.webpage-list-tool {
padding: 7px 10px;
}
.webpage-import-button {
background-color: green;
color: white;
}
.webpage-import-button:hover {
background-color: darkgreen;
}
/* SQUARED TWO */
.squaredTwo {
width: 28px;
height: 28px;
background: #fcfff4;
background: -webkit-linear-gradient(top, #fcfff4 0%, #dfe5d7 40%, #b3bead 100%);
background: -moz-linear-gradient(top, #fcfff4 0%, #dfe5d7 40%, #b3bead 100%);
background: -o-linear-gradient(top, #fcfff4 0%, #dfe5d7 40%, #b3bead 100%);
background: -ms-linear-gradient(top, #fcfff4 0%, #dfe5d7 40%, #b3bead 100%);
background: linear-gradient(top, #fcfff4 0%, #dfe5d7 40%, #b3bead 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fcfff4', endColorstr='#b3bead',GradientType=0 );
margin: 20px auto;
-webkit-box-shadow: inset 0px 1px 1px white, 0px 1px 3px rgba(0,0,0,0.5);
-moz-box-shadow: inset 0px 1px 1px white, 0px 1px 3px rgba(0,0,0,0.5);
box-shadow: inset 0px 1px 1px white, 0px 1px 3px rgba(0,0,0,0.5);
position: relative;
}
.squaredTwo label {
cursor: pointer;
position: absolute;
width: 20px;
height: 20px;
left: 4px;
top: 4px;
-webkit-box-shadow: inset 0px 1px 1px rgba(0,0,0,0.5), 0px 1px 0px rgba(255,255,255,1);
-moz-box-shadow: inset 0px 1px 1px rgba(0,0,0,0.5), 0px 1px 0px rgba(255,255,255,1);
box-shadow: inset 0px 1px 1px rgba(0,0,0,0.5), 0px 1px 0px rgba(255,255,255,1);
background: -webkit-linear-gradient(top, #222 0%, #45484d 100%);
background: -moz-linear-gradient(top, #222 0%, #45484d 100%);
background: -o-linear-gradient(top, #222 0%, #45484d 100%);
background: -ms-linear-gradient(top, #222 0%, #45484d 100%);
background: linear-gradient(top, #222 0%, #45484d 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#222', endColorstr='#45484d',GradientType=0 );
}
.squaredTwo label:after {
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
filter: alpha(opacity=0);
opacity: 0;
content: '';
position: absolute;
width: 9px;
height: 5px;
background: transparent;
top: 4px;
left: 4px;
border: 3px solid #fcfff4;
border-top: none;
border-right: none;
-webkit-transform: rotate(-45deg);
-moz-transform: rotate(-45deg);
-o-transform: rotate(-45deg);
-ms-transform: rotate(-45deg);
transform: rotate(-45deg);
}
.squaredTwo label:hover::after {
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=30)";
filter: alpha(opacity=30);
opacity: 0.3;
}
.squaredTwo input[type=checkbox]:checked + label:after {
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";
filter: alpha(opacity=100);
opacity: 1;
}

15
view/js/mod_webpages.js Normal file
View File

@ -0,0 +1,15 @@
$(document).ready(function() {
$("input[type=\"checkbox\"]").hide();
});
window.isChecked = true;
function checkedAll(isChecked) {
window.isChecked = !window.isChecked ;
var c = document.getElementsByTagName('input');
for (var i = 0; i < c.length; i++){
if (c[i].type == 'checkbox'){
c[i].checked = isChecked;
}
}
}

View File

@ -1,3 +1,4 @@
[region=aside]
[widget=design_tools][/widget]
[widget=website_import_tools][/widget]
[/region]

126
view/tpl/webpage_import.tpl Normal file
View File

@ -0,0 +1,126 @@
<div class="generic-content-wrapper">
<form action="" method="post" autocomplete="on" >
<input type="hidden" name="action" value="importselected">
<div class="section-title-wrapper">
<div class="pull-right">
<button class="btn btn-md btn-success" type="submit" name="submit" value="{{$importbtn}}">{{$importbtn}}</button>
</div>
<h2>{{$title}}</h2>
<div class="clear"></div>
</div>
<div id="import-website-content-wrapper" class="section-content-wrapper">
<div class="pull-left">
<button id="toggle-select-all" class="btn btn-xs btn-primary" onclick="checkedAll(window.isChecked); return false;"><i class="fa fa-check"></i>&nbsp;Toggle Select All</button>
</div>
<div class="clear"></div>
<h4>Scanned Pages</h4>
<div>
<table class="table-striped table-responsive table-hover" style="width: 100%;">
<tr><td>Import?</td><td>Page</td><!--<td>Existing Page</td>--></tr>
{{foreach $pages as $page}}
<tr>
<td>
<div class='squaredTwo'>
<input type="checkbox" id="page_{{$page.pagelink}}" name="page[]" value="{{$page.pagelink}}">
<label for="page_{{$page.pagelink}}"></label>
</div>
</td>
<td>
<div class='desc'>
Page Link: {{$page.pagelink}}<br>
Layout: {{$page.layout}}<br>
Title: {{$page.title}}<br>
Content File: {{$page.contentfile}}<br>
Type: {{$page.type}}<br>
</div>
</td>
<!-- TODO: Retrieve existing element information to avoid accidental overwriting
<td>
<div class='desc'>
Name: {{$page.curpage.pagelink}}<br>
Layout: {{$page.curpage.layout}}<br>
Title: {{$page.curpage.title}}<br>
Last edit: {{$page.curpage.edited}}<br>
Type: {{$page.curpage.type}}<br>
</div>
</td>
-->
</tr>
{{/foreach}}
</table>
</div>
<h4>Scanned Layouts</h4>
<div>
<table class="table-striped table-responsive table-hover" style="width: 100%;">
<tr><td>Import?</td><td>Layout</td><!--<td>Existing Layout</td>--></tr>
{{foreach $layouts as $layout}}
<tr>
<td>
<div class='squaredTwo'>
<input type="checkbox" id="layout_{{$layout.name}}" name="layout[]" value="{{$layout.name}}">
<label for="layout_{{$layout.name}}"></label>
</div>
</td>
<td>
<div class='desc'>
Name: {{$layout.name}}<br>
Description: {{$layout.description}}<br>
Content File: {{$layout.contentfile}}<br>
</div>
</td>
<!-- TODO: Retrieve existing element information to avoid accidental overwriting
<td>
<div class='desc'>
Name: {{$layout.curblock.name}}<br>
Title: {{$layout.curblock.description}}<br>
Last edit: {{$layout.curblock.edited}}<br>
</div>
</td>
-->
</tr>
{{/foreach}}
</table>
</div>
<h4>Scanned Blocks</h4>
<div>
<table class="table-striped table-responsive table-hover" style="width: 100%;">
<tr><td>Import?</td><td>Block</td><!--<td>Existing Block</td>--></tr>
{{foreach $blocks as $block}}
<tr>
<td>
<div class='squaredTwo'>
<input type="checkbox" id="block_{{$block.name}}" name="block[]" value="{{$block.name}}">
<label for="block_{{$block.name}}"></label>
</div>
</td>
<td>
<div class='desc'>
Name: {{$block.name}}<br>
Title: {{$block.title}}<br>
Content File: {{$block.contentfile}}<br>
Type: {{$block.type}}<br>
</div>
</td>
<!-- TODO: Retrieve existing element information to avoid accidental overwriting
<td>
<div class='desc'>
Name: {{$block.curblock.name}}<br>
Title: {{$block.curblock.title}}<br>
Last edit: {{$block.curblock.edited}}<br>
Type: {{$block.curblock.type}}<br>
</div>
</td>
-->
</tr>
{{/foreach}}
</table>
</div>
</div>
<div class="clear"></div>
</form>
</div>

View File

@ -0,0 +1,37 @@
<div id="website-import-tools" class="widget">
<h3>{{$title}}</h3>
<ul class="nav nav-pills nav-stacked">
<li>
<a href="#" onclick="openClose('import-form');
return false;"><i class="fa fa-cloud-upload generic-icons"></i> {{$import_label}}</a>
</li>
<li>
<form id="import-form" enctype="multipart/form-data" method="post" action="" style="display: none;" class="sub-menu">
<input type="hidden" name="action" value="scan">
<p style="margin-top: 20px;" class="descriptive-text">{{$file_import_text}}</p>
<div class="form-group">
<div class="input-group">
<input class="widget-input" type="text" name="path" title="{{$hint}}" placeholder="{{$desc}}" />
<div class="input-group-btn">
<button class="btn btn-default btn-sm" type="submit" name="cloudsubmit" value="{{$select}}"><i class="fa fa-folder-open generic-icons"></i></button>
</div>
</div>
</div>
<!-- Or upload a zipped file containing the website -->
<p class="descriptive-text">{{$file_upload_text}}</p>
<div class="form-group">
<div class="input-group">
<input class="widget-input" type="file" name="zip_file" />
<div class="input-group-btn">
<button class="btn btn-default btn-sm" type="submit" name="w_upload" value="w_upload"><i class="fa fa-file-archive-o generic-icons"></i></button>
</div>
</div>
</div>
</form>
</li>
</ul>
</div>