forked from mirror/MrDoc
v0.5.5 更新内容详见CHANGES.MD
This commit is contained in:
parent
052b717b07
commit
2a5e2846b7
@ -1,10 +1,17 @@
|
||||
## 版本更新记录
|
||||
|
||||
### v0.5.5
|
||||
### v0.5.5 2020-07-20
|
||||
|
||||
- 禁用编辑器页面的列表目录和下拉目录语法解析
|
||||
- Chrome扩展添加鼠标选择控制选项
|
||||
- 优化文档样式
|
||||
- 添加文集导入功能
|
||||
- 优化文集目录加载速度
|
||||
- 编辑器支持音视频外链和视频网站外链
|
||||
- 编辑器添加字符统计功能
|
||||
- 优化文档页面分享样式
|
||||
- 优化文档编辑器排版布局
|
||||
- 新增图片上传的URL链接插入
|
||||
|
||||
### v0.5.4
|
||||
|
||||
|
@ -40,7 +40,7 @@ SECRET_KEY = '5&71mt9@^58zdg*_!t(x6g14q*@84d%ptr%%s6e0l50zs0we3d'
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = CONFIG.getboolean('site','debug')
|
||||
|
||||
VERSIONS = '0.5.4'
|
||||
VERSIONS = '0.5.5'
|
||||
|
||||
ALLOWED_HOSTS = ['*']
|
||||
|
||||
|
147
app_doc/import_utils.py
Normal file
147
app_doc/import_utils.py
Normal file
@ -0,0 +1,147 @@
|
||||
# coding:utf-8
|
||||
# @文件: import_utils.py
|
||||
# @创建者:州的先生
|
||||
# #日期:2020/6/17
|
||||
# 博客地址:zmister.com
|
||||
# 文集导入相关方法
|
||||
|
||||
import shutil
|
||||
import os
|
||||
import time
|
||||
import re
|
||||
from app_doc.models import Doc,Project,Image
|
||||
from app_doc.util_upload_img import upload_generation_dir
|
||||
from django.db import transaction
|
||||
from django.conf import settings
|
||||
from loguru import logger
|
||||
|
||||
# 导入Zip文集
|
||||
class ImportZipProject():
|
||||
# 读取 Zip 压缩包
|
||||
def read_zip(self,zip_file_path,create_user):
|
||||
# 导入流程:
|
||||
# 1、解压zip压缩包文件到temp文件夹
|
||||
# 2、遍历temp文件夹内的解压后的.md文件
|
||||
# 3、读取.md文件的文本内容
|
||||
# 4、如果里面匹配到相对路径的静态文件,从指定文件夹里面读取
|
||||
# 5、上传图片,写入数据库,修改.md文件里面的url路径
|
||||
|
||||
# 新建一个临时文件夹,用于存放解压的文件
|
||||
self.temp_dir = zip_file_path[:-3]
|
||||
os.mkdir(self.temp_dir)
|
||||
# 解压 zip 文件到指定临时文件夹
|
||||
shutil.unpack_archive(zip_file_path, extract_dir=self.temp_dir)
|
||||
|
||||
# 处理文件夹和文件名的中文乱码
|
||||
for root, dirs, files in os.walk(self.temp_dir):
|
||||
for dir in dirs:
|
||||
try:
|
||||
new_dir = dir.encode('cp437').decode('gbk')
|
||||
except:
|
||||
new_dir = dir.encode('utf-8').decode('utf-8')
|
||||
# print(new_dir)
|
||||
os.rename(os.path.join(root, dir), os.path.join(root, new_dir))
|
||||
|
||||
for file in files:
|
||||
try:
|
||||
new_file = file.encode('cp437').decode('gbk')
|
||||
except:
|
||||
new_file = file.encode('utf-8').decode('utf-8')
|
||||
# print(root, new_file)
|
||||
os.rename(os.path.join(root, file), os.path.join(root, new_file))
|
||||
|
||||
# 开启事务
|
||||
with transaction.atomic():
|
||||
save_id = transaction.savepoint()
|
||||
try:
|
||||
# 新建文集
|
||||
project = Project.objects.create(
|
||||
name=zip_file_path[:-4].split('/')[-1],
|
||||
intro='',
|
||||
role=1,
|
||||
create_user=create_user
|
||||
)
|
||||
# 遍历临时文件夹中的所有文件和文件夹
|
||||
for f in os.listdir(self.temp_dir):
|
||||
# 获取 .md 文件
|
||||
if f.endswith('.md'):
|
||||
# print(f)
|
||||
# 读取 .md 文件文本内容
|
||||
with open(os.path.join(self.temp_dir,f),'r',encoding='utf-8') as md_file:
|
||||
md_content = md_file.read()
|
||||
md_content = self.operat_md_media(md_content,create_user)
|
||||
# 新建文档
|
||||
doc = Doc.objects.create(
|
||||
name = f[:-3],
|
||||
pre_content = md_content,
|
||||
top_doc = project.id,
|
||||
status = 0,
|
||||
create_user = create_user
|
||||
)
|
||||
except:
|
||||
logger.exception("解析导入文件异常")
|
||||
# 回滚事务
|
||||
transaction.savepoint_rollback(save_id)
|
||||
|
||||
transaction.savepoint_commit(save_id)
|
||||
try:
|
||||
shutil.rmtree(self.temp_dir)
|
||||
os.remove(zip_file_path)
|
||||
return project.id
|
||||
except:
|
||||
logger.exception("删除临时文件异常")
|
||||
return None
|
||||
|
||||
|
||||
# 处理MD内容中的静态文件
|
||||
def operat_md_media(self,md_content,create_user):
|
||||
# 查找MD内容中的静态文件
|
||||
pattern = r"\!\[.*?\]\(.*?\)"
|
||||
media_list = re.findall(pattern, md_content)
|
||||
# print(media_list)
|
||||
# 存在静态文件,进行遍历
|
||||
if len(media_list) > 0:
|
||||
for media in media_list:
|
||||
media_filename = media.split("(")[-1].split(")")[0] # 媒体文件的文件名
|
||||
# 存在本地图片路径
|
||||
if media_filename.startswith("./"):
|
||||
# 获取文件后缀
|
||||
file_suffix = media_filename.split('.')[-1]
|
||||
if file_suffix.lower() not in settings.ALLOWED_IMG:
|
||||
continue
|
||||
# 判断本地图片路径是否存在
|
||||
temp_media_file_path = os.path.join(self.temp_dir,media_filename[2:])
|
||||
if os.path.exists(temp_media_file_path):
|
||||
# 如果存在,上传本地图片
|
||||
print(media_filename)
|
||||
dir_name = upload_generation_dir() # 获取当月文件夹名称
|
||||
|
||||
# 复制文件到媒体文件夹
|
||||
copy2_filename = dir_name + '/' + str(time.time()) + '.' + file_suffix
|
||||
new_media_file_path = shutil.copy2(
|
||||
temp_media_file_path,
|
||||
settings.MEDIA_ROOT + copy2_filename
|
||||
)
|
||||
|
||||
# 替换MD内容的静态文件链接
|
||||
new_media_filename = new_media_file_path.split(settings.MEDIA_ROOT,1)[-1]
|
||||
new_media_filename = '/media' + new_media_filename
|
||||
|
||||
# 图片数据写入数据库
|
||||
Image.objects.create(
|
||||
user=create_user,
|
||||
file_path=new_media_filename,
|
||||
file_name=str(time.time())+'.'+file_suffix,
|
||||
remark='本地上传',
|
||||
)
|
||||
md_content = md_content.replace(media_filename, new_media_filename)
|
||||
else:
|
||||
pass
|
||||
return md_content
|
||||
# 不存在静态文件,直接返回MD内容
|
||||
else:
|
||||
return md_content
|
||||
|
||||
if __name__ == '__main__':
|
||||
imp = ImportZipProject()
|
||||
imp.read_zip(r"D:\Python XlsxWriter模块中文文档_2020-06-16.zip")
|
118
app_doc/import_views.py
Normal file
118
app_doc/import_views.py
Normal file
@ -0,0 +1,118 @@
|
||||
# coding:utf-8
|
||||
# @文件: import_views.py
|
||||
# @创建者:州的先生
|
||||
# #日期:2020/6/17
|
||||
# 博客地址:zmister.com
|
||||
# 文集导入相关视图函数
|
||||
|
||||
from django.shortcuts import render,redirect
|
||||
from django.http.response import JsonResponse,Http404,HttpResponseNotAllowed,HttpResponse
|
||||
from django.http import HttpResponseForbidden
|
||||
from django.contrib.auth.decorators import login_required # 登录需求装饰器
|
||||
from django.views.decorators.http import require_http_methods,require_GET,require_POST # 视图请求方法装饰器
|
||||
from django.core.paginator import Paginator,PageNotAnInteger,EmptyPage,InvalidPage # 后端分页
|
||||
from django.core.exceptions import PermissionDenied,ObjectDoesNotExist
|
||||
from app_doc.models import Project,Doc,DocTemp
|
||||
from django.contrib.auth.models import User
|
||||
from django.db.models import Q
|
||||
from django.db import transaction
|
||||
from loguru import logger
|
||||
import datetime
|
||||
import traceback
|
||||
import re
|
||||
from app_doc.report_utils import *
|
||||
from app_admin.decorators import check_headers,allow_report_file
|
||||
import os.path
|
||||
import json
|
||||
from app_doc.import_utils import *
|
||||
|
||||
# 导入文集
|
||||
@login_required()
|
||||
@require_http_methods(['GET','POST'])
|
||||
def import_project(request):
|
||||
if request.method == 'GET':
|
||||
return render(request,'app_doc/manage_project_import.html',locals())
|
||||
elif request.method == 'POST':
|
||||
file_type = request.POST.get('type',None)
|
||||
# 上传Zip压缩文件
|
||||
if file_type == 'zip':
|
||||
import_file = request.FILES.get('import_file',None)
|
||||
if import_file:
|
||||
file_name = import_file.name
|
||||
# 限制文件大小在50mb以内
|
||||
if import_file.size > 52428800:
|
||||
return JsonResponse({'status': False, 'data': '文件大小超出限制'})
|
||||
# 限制文件格式为.zip
|
||||
if file_name.endswith('.zip'):
|
||||
if os.path.exists(os.path.join(settings.MEDIA_ROOT,'import_temp')) is False:
|
||||
os.mkdir(os.path.join(settings.MEDIA_ROOT,'import_temp'))
|
||||
temp_file_name = str(time.time())+'.zip'
|
||||
temp_file_path = os.path.join(settings.MEDIA_ROOT,'import_temp/'+temp_file_name)
|
||||
with open(temp_file_path,'wb+') as zip_file:
|
||||
for chunk in import_file:
|
||||
zip_file.write(chunk)
|
||||
if os.path.exists(temp_file_path):
|
||||
import_file = ImportZipProject()
|
||||
project = import_file.read_zip(temp_file_path,request.user)
|
||||
if project:
|
||||
docs = Doc.objects.filter(top_doc=project).values_list('id','name')
|
||||
doc_list = [doc for doc in docs]
|
||||
return JsonResponse({'status':True,'data':doc_list,'id':project})
|
||||
else:
|
||||
return JsonResponse({'status':False,'data':'上传失败'})
|
||||
else:
|
||||
return JsonResponse({'status':False,'data':'上传失败'})
|
||||
else:
|
||||
return JsonResponse({'status':False,'data':'仅支持.zip格式'})
|
||||
else:
|
||||
return JsonResponse({'status':False,'data':'无有效文件'})
|
||||
else:
|
||||
return JsonResponse({'status':False,'data':'参数错误'})
|
||||
|
||||
|
||||
# 文集文档排序
|
||||
@login_required()
|
||||
@require_http_methods(['POST'])
|
||||
def project_doc_sort(request):
|
||||
project_id = request.POST.get('pid',None) # 文集ID
|
||||
title = request.POST.get('title',None) # 文集名称
|
||||
desc = request.POST.get('desc',None) # 文集简介
|
||||
role = request.POST.get('role',1) # 文集权限
|
||||
sort_data = request.POST.get('sort_data','[]') # 文档排序列表
|
||||
doc_status = request.POST.get('status',0) # 文档状态
|
||||
# print(sort_data)
|
||||
try:
|
||||
sort_data = json.loads(sort_data)
|
||||
except Exception:
|
||||
return JsonResponse({'status':False,'data':'文档参数错误'})
|
||||
|
||||
try:
|
||||
Project.objects.get(id=project_id,create_user=request.user)
|
||||
except ObjectDoesNotExist:
|
||||
return JsonResponse({'status':False,'data':'没有匹配的文集'})
|
||||
|
||||
# 修改文集信息
|
||||
Project.objects.filter(id=project_id).update(
|
||||
name = title,
|
||||
intro = desc,
|
||||
role = role
|
||||
)
|
||||
# 文档排序
|
||||
n = 10
|
||||
# 第一级文档
|
||||
for data in sort_data:
|
||||
Doc.objects.filter(id=data['id']).update(sort = n,status=doc_status)
|
||||
n += 10
|
||||
# 存在第二级文档
|
||||
if 'children' in data.keys():
|
||||
n1 = 10
|
||||
for c1 in data['children']:
|
||||
Doc.objects.filter(id=c1['id']).update(sort = n1,parent_doc=data['id'],status=doc_status)
|
||||
n1 += 10
|
||||
# 存在第三级文档
|
||||
if 'children' in c1.keys():
|
||||
n2 = 10
|
||||
for c2 in c1['children']:
|
||||
Doc.objects.filter(id=c2['id']).update(sort=n2,parent_doc=c1['id'],status=doc_status)
|
||||
|
||||
return JsonResponse({'status':True,'data':'ok'})
|
@ -1,5 +1,5 @@
|
||||
from django.urls import path,re_path
|
||||
from app_doc import views,util_upload_img
|
||||
from app_doc import views,util_upload_img,import_views
|
||||
|
||||
urlpatterns = [
|
||||
path('',views.project_list,name='pro_list'),# 文档首页
|
||||
@ -19,6 +19,8 @@ urlpatterns = [
|
||||
path('check_viewcode/',views.check_viewcode,name='check_viewcode'),# 文集访问码验证
|
||||
path('manage_project_colla/<int:pro_id>/',views.manage_project_collaborator,name="manage_pro_colla"), # 管理文集协作
|
||||
path('manage_pro_colla_self/',views.manage_pro_colla_self,name="manage_pro_colla_self"), # 我协作的文集
|
||||
path('manage_project_import/',import_views.import_project,name="import_project"), # 导入文集
|
||||
path('manage_project_doc_sort/',import_views.project_doc_sort,name='project_doc_sort'), # 导入文集文档排序
|
||||
#################文档相关
|
||||
path('project-<int:pro_id>/doc-<int:doc_id>/', views.doc, name='doc'), # 文档浏览页
|
||||
path('create_doc/', views.create_doc, name="create_doc"), # 新建文档
|
||||
|
@ -1298,47 +1298,52 @@ def get_pro_doc(request):
|
||||
def get_pro_doc_tree(request):
|
||||
pro_id = request.POST.get('pro_id', None)
|
||||
if pro_id:
|
||||
# 获取一级文档
|
||||
# 查询存在上级文档的文档
|
||||
parent_id_list = Doc.objects.filter(top_doc=pro_id,status=1).exclude(parent_doc=0).values_list('parent_doc',flat=True)
|
||||
# 获取存在上级文档的上级文档ID
|
||||
# print(parent_id_list)
|
||||
doc_list = []
|
||||
# 获取一级文档
|
||||
top_docs = Doc.objects.filter(top_doc=pro_id,parent_doc=0,status=1).values('id','name').order_by('sort')
|
||||
# 遍历一级文档
|
||||
for doc in top_docs:
|
||||
top_item = {
|
||||
'id':doc['id'],
|
||||
'field':doc['name'],
|
||||
'title':doc['name'],
|
||||
'href':'/project-{}/doc-{}/'.format(pro_id,doc['id']),
|
||||
'spread':True,
|
||||
'level':1
|
||||
}
|
||||
# 获取二级文档
|
||||
sec_docs = Doc.objects.filter(top_doc=pro_id,parent_doc=doc['id'],status=1).values('id','name').order_by('sort')
|
||||
if sec_docs.exists():# 二级文档
|
||||
# 如果一级文档存在下级文档,查询其二级文档
|
||||
if doc['id'] in parent_id_list:
|
||||
# 获取二级文档
|
||||
sec_docs = Doc.objects.filter(top_doc=pro_id,parent_doc=doc['id'],status=1).values('id','name').order_by('sort')
|
||||
top_item['children'] = []
|
||||
for doc in sec_docs:
|
||||
sec_item = {
|
||||
'id': doc['id'],
|
||||
'field': doc['name'],
|
||||
'title': doc['name'],
|
||||
'href': '/project-{}/doc-{}/'.format(pro_id, doc['id']),
|
||||
'level':2
|
||||
}
|
||||
# 获取三级文档
|
||||
thr_docs = Doc.objects.filter(top_doc=pro_id,parent_doc=doc['id'],status=1).values('id','name').order_by('sort')
|
||||
if thr_docs.exists():
|
||||
# 如果二级文档存在下级文档,查询第三级文档
|
||||
if doc['id'] in parent_id_list:
|
||||
# 获取三级文档
|
||||
thr_docs = Doc.objects.filter(top_doc=pro_id,parent_doc=doc['id'],status=1).values('id','name').order_by('sort')
|
||||
sec_item['children'] = []
|
||||
for doc in thr_docs:
|
||||
item = {
|
||||
'id': doc['id'],
|
||||
'field': doc['name'],
|
||||
'title': doc['name'],
|
||||
'href': '/project-{}/doc-{}/'.format(pro_id, doc['id']),
|
||||
'level': 3
|
||||
}
|
||||
sec_item['children'].append(item)
|
||||
top_item['children'].append(sec_item)
|
||||
top_item['children'].append(sec_item)
|
||||
else:
|
||||
top_item['children'].append(sec_item)
|
||||
doc_list.append(top_item)
|
||||
# 如果一级文档没有下级文档,直接保存
|
||||
else:
|
||||
doc_list.append(top_item)
|
||||
return JsonResponse({'status':True,'data':doc_list})
|
||||
|
@ -3478,6 +3478,94 @@
|
||||
var editormdLogoReg = regexs.editormdLogo;
|
||||
var pageBreakReg = regexs.pageBreak;
|
||||
|
||||
// marked 解析图片
|
||||
markedRenderer.image = function(href,title,text) {
|
||||
var attr = "";
|
||||
var begin = "";
|
||||
var end = "";
|
||||
// console.log(href,title,text)
|
||||
if(/^=(.*?)/.test(text)){
|
||||
console.log(text)
|
||||
switch(text){
|
||||
case '=video':
|
||||
if(href.match(/^.+.(mp4|m4v|ogg|ogv|webm)$/)){
|
||||
return "<video src='"+ href + "' controls='controls' preload width=500></video>"
|
||||
}
|
||||
break;
|
||||
case '=audio':
|
||||
if(href.match(/^.+.(mp3|wav|flac|m4a)$/)){
|
||||
return "<audio src='"+ href + "' controls='controls'></audio>"
|
||||
}
|
||||
break;
|
||||
case '=video_iframe':
|
||||
const youtubeMatch = href.match(/\/\/(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))([\w|-]{11})(?:(?:[\?&]t=)(\S+))?/);
|
||||
const youkuMatch = href.match(/\/\/v\.youku\.com\/v_show\/id_(\w+)=*\.html/);
|
||||
const qqMatch = href.match(/\/\/v\.qq\.com\/x\/cover\/.*\/([^\/]+)\.html\??.*/);
|
||||
const coubMatch = href.match(/(?:www\.|\/\/)coub\.com\/view\/(\w+)/);
|
||||
const facebookMatch = href.match(/(?:www\.|\/\/)facebook\.com\/([^\/]+)\/videos\/([0-9]+)/);
|
||||
const dailymotionMatch = href.match(/.+dailymotion.com\/(video|hub)\/(\w+)\?/);
|
||||
const bilibiliMatch = href.match(/(?:www\.|\/\/)bilibili\.com\/video\/(\w+)/);
|
||||
const tedMatch = href.match(/(?:www\.|\/\/)ted\.com\/talks\/(\w+)/);
|
||||
|
||||
if (youtubeMatch && youtubeMatch[1].length === 11) {
|
||||
return `<iframe height=400 width=500 frameborder=0 allowfullscreen src="//www.youtube.com/embed/${youtubeMatch[1] + (youtubeMatch[2] ? "?start=" + youtubeMatch[2] : "")}">`
|
||||
} else if (youkuMatch && youkuMatch[1]) {
|
||||
return `<iframe height=400 width=500 frameborder=0 allowfullscreen src="//player.youku.com/embed/${youkuMatch[1]}">`
|
||||
} else if (qqMatch && qqMatch[1]) {
|
||||
return `<iframe height=400 width=500 frameborder=0 allowfullscreen src="https://v.qq.com/txp/iframe/player.html?vid=${qqMatch[1]}">`
|
||||
} else if (coubMatch && coubMatch[1]) {
|
||||
return `<iframe height=400 width=500 frameborder=0 allowfullscreen src="//coub.com/embed/${coubMatch[1]}?muted=false&autostart=false&originalSize=true&startWithHD=true">`
|
||||
} else if (facebookMatch && facebookMatch[0]) {
|
||||
return `<iframe height=400 width=500 frameborder=0 allowfullscreen src="https://www.facebook.com/plugins/video.php?href=${encodeURIComponent(facebookMatch[0])}">`
|
||||
} else if (dailymotionMatch && dailymotionMatch[2]) {
|
||||
return `<iframe height=400 width=500 frameborder=0 allowfullscreen src="https://www.dailymotion.com/embed/video/${dailymotionMatch[2]}">`
|
||||
} else if (bilibiliMatch && bilibiliMatch[1]) {
|
||||
return `<iframe height=400 width=500 frameborder=0 allowfullscreen src="//player.bilibili.com/player.html?bvid=${bilibiliMatch[1]}">`
|
||||
} else if (tedMatch && tedMatch[1]) {
|
||||
return `<iframe height=400 width=500 frameborder=0 allowfullscreen src="//embed.ted.com/talks/${tedMatch[1]}">`
|
||||
}
|
||||
// return '<iframe height=400 width=500 src="' + href +'" frameborder=0 allowfullscreen />'
|
||||
}
|
||||
}
|
||||
|
||||
if(href && href !== ""){
|
||||
var a = document.createElement('a');
|
||||
a.href = href;
|
||||
var attrs = a.hash.match(/size=\d+x\d+/i);
|
||||
if(attrs !== null) {
|
||||
a.hash = a.hash.replace(attrs[0],"");
|
||||
href = a.href;
|
||||
attrs = attrs[0].replace("size=","").split("x");
|
||||
if(attrs[0] > 0) {
|
||||
attr += " width=\"" + attrs[0] + "\""
|
||||
}
|
||||
if(attrs[1] > 0) {
|
||||
attr += " height=\"" + attrs[1] + "\""
|
||||
}
|
||||
}
|
||||
attrs = a.hash.match(/align=(center|left|right)/i)
|
||||
if (attrs !== null) {
|
||||
var hash = a.hash.replace(attrs[0],"");
|
||||
if (hash.indexOf("#&") === 0) {
|
||||
hash = "#" + hash.substr(2);
|
||||
}
|
||||
a.hash = hash;
|
||||
|
||||
href = a.href;
|
||||
attrs = attrs[0].replace("align=","");
|
||||
end = "</p>";
|
||||
if(attrs === "center"){
|
||||
begin = '<p align="center">';
|
||||
}else if (attrs === "left") {
|
||||
begin = '<p align="left">';
|
||||
}else if (attrs === "right") {
|
||||
begin = '<p align="right">';
|
||||
}
|
||||
}
|
||||
}
|
||||
return begin + "<img src=\""+href+"\" title=\""+title+"\" alt=\""+text+"\" "+attr+">" + end;
|
||||
};
|
||||
|
||||
// marked emoji 解析
|
||||
markedRenderer.emoji = function(text) {
|
||||
|
||||
|
257
static/mrdoc.css
257
static/mrdoc.css
@ -270,9 +270,12 @@ body, html {
|
||||
.doc-summary ul.summary li a:hover,.bq a:hover{
|
||||
text-decoration: underline;
|
||||
}
|
||||
/* 文档目前当前链接 */
|
||||
li.active > a,li.active > div > a{
|
||||
color: #5FB878;
|
||||
font-weight:700;
|
||||
}
|
||||
|
||||
.bq a {
|
||||
padding: 15px;
|
||||
border-bottom: none;
|
||||
@ -402,6 +405,260 @@ li.active > a,li.active > div > a{
|
||||
color:#e91e63 !important;
|
||||
}
|
||||
|
||||
/* 自定义按钮样式 */
|
||||
.mrdoc-btn-default:hover{
|
||||
border-color:#1E9FFF;
|
||||
color:#1E9FFF;
|
||||
}
|
||||
|
||||
/* 文字悬浮提示样式 */
|
||||
/* tooltip样式 */
|
||||
[tooltip] {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
[tooltip]::after {
|
||||
display: none;
|
||||
content: attr(tooltip);
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
padding: 8px 15px;
|
||||
max-width: 200px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 10px 20px -5px rgba(0, 0, 0, 0.4);
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
[tooltip]::before {
|
||||
display: none;
|
||||
content: '';
|
||||
position: absolute;
|
||||
border: 5px solid transparent;
|
||||
border-bottom-width: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
[tooltip]:hover::after {
|
||||
display: block;
|
||||
}
|
||||
|
||||
[tooltip]:hover::before {
|
||||
display: block;
|
||||
}
|
||||
|
||||
[tooltip][placement^="top"]::after, [tooltip][placement^="top"]::before {
|
||||
animation: anime-top 300ms ease-out forwards;
|
||||
}
|
||||
|
||||
[tooltip][placement^="right"]::after, [tooltip][placement^="right"]::before {
|
||||
animation: anime-right 300ms ease-out forwards;
|
||||
}
|
||||
|
||||
[tooltip][placement^="bottom"]::after, [tooltip][placement^="bottom"]::before {
|
||||
animation: anime-bottom 300ms ease-out forwards;
|
||||
}
|
||||
|
||||
[tooltip][placement^="left"]::after, [tooltip][placement^="left"]::before {
|
||||
animation: anime-left 300ms ease-out forwards;
|
||||
}
|
||||
|
||||
/* 气泡主题 */
|
||||
.tooltip-theme-dark, [tooltip]::after {
|
||||
color: #fff;
|
||||
background-color: #313131;
|
||||
}
|
||||
|
||||
.tooltip-theme-light, [tooltip][effect="light"]::after {
|
||||
color: #313131;
|
||||
background-color: #fff;
|
||||
border: 1px solid #313131;
|
||||
}
|
||||
|
||||
/* 气泡位置 */
|
||||
/*----上----*/
|
||||
.tooltip-placement-top, [tooltip]:not([placement])::after, [tooltip][placement=""]::after, [tooltip][placement="top"]::after {
|
||||
bottom: calc(100% + 10px);
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
}
|
||||
|
||||
.tooltip-placement-top-right, [tooltip][placement="top-right"]::after {
|
||||
bottom: calc(100% + 10px);
|
||||
left: 100%;
|
||||
transform: translate(-100%, 0);
|
||||
}
|
||||
|
||||
.tooltip-placement-top-left, [tooltip][placement="top-left"]::after {
|
||||
bottom: calc(100% + 10px);
|
||||
left: 0;
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
|
||||
/*----右----*/
|
||||
.tooltip-placement-right, [tooltip][placement="right"]::after {
|
||||
left: calc(100% + 10px);
|
||||
top: 50%;
|
||||
transform: translate(0, -50%);
|
||||
}
|
||||
|
||||
.tooltip-placement-right-top, [tooltip][placement="right-top"]::after {
|
||||
left: calc(100% + 10px);
|
||||
top: 0;
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
|
||||
.tooltip-placement-right-bottom, [tooltip][placement="right-bottom"]::after {
|
||||
left: calc(100% + 10px);
|
||||
top: 100%;
|
||||
transform: translate(0, -100%);
|
||||
}
|
||||
|
||||
/*----下----*/
|
||||
.tooltip-placement-bottom, [tooltip][placement="bottom"]::after {
|
||||
top: calc(100% + 10px);
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
}
|
||||
|
||||
.tooltip-placement-bottom-right, [tooltip][placement="bottom-right"]::after {
|
||||
top: calc(100% + 10px);
|
||||
left: 100%;
|
||||
transform: translate(-100%, 0);
|
||||
}
|
||||
|
||||
.tooltip-placement-bottom-left, [tooltip][placement="bottom-left"]::after {
|
||||
top: calc(100% + 10px);
|
||||
left: 0;
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
|
||||
/*----左----*/
|
||||
.tooltip-placement-left, [tooltip][placement="left"]::after {
|
||||
right: calc(100% + 10px);
|
||||
top: 50%;
|
||||
transform: translate(0, -50%);
|
||||
}
|
||||
|
||||
.tooltip-placement-left-top, [tooltip][placement="left-top"]::after {
|
||||
right: calc(100% + 10px);
|
||||
top: 0;
|
||||
transform: translate(0, 0);
|
||||
}
|
||||
|
||||
.tooltip-placement-left-bottom, [tooltip][placement="left-bottom"]::after {
|
||||
right: calc(100% + 10px);
|
||||
top: 100%;
|
||||
transform: translate(0, -100%);
|
||||
}
|
||||
|
||||
/* 三角形主题 */
|
||||
.triangle-theme-dark, [tooltip]::before {
|
||||
border-top-color: #313131;
|
||||
}
|
||||
|
||||
.triangle-theme-light, [tooltip][effect="light"]::before {
|
||||
border-top-color: #313131;
|
||||
}
|
||||
|
||||
/* 三角形位置 */
|
||||
/*----上----*/
|
||||
.triangle-placement-top, [tooltip]:not([placement])::before, [tooltip][placement=""]::before, [tooltip][placement="top"]::before {
|
||||
bottom: calc(100% + 5px);
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
}
|
||||
|
||||
.triangle-placement-top-left, [tooltip][placement="top-left"]::before {
|
||||
bottom: calc(100% + 5px);
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.triangle-placement-top-right, [tooltip][placement="top-right"]::before {
|
||||
bottom: calc(100% + 5px);
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
/*----右----*/
|
||||
.triangle-placement-right, [tooltip][placement="right"]::before, .triangle-placement-right-top, [tooltip][placement="right-top"]::before, .triangle-placement-right-bottom, [tooltip][placement="right-bottom"]::before {
|
||||
left: calc(100% + 3px);
|
||||
top: 50%;
|
||||
transform: translate(0, -50%) rotateZ(90deg);
|
||||
}
|
||||
|
||||
.triangle-placement-right-top, [tooltip][placement="right-top"]::before {
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
.triangle-placement-right-bottom, [tooltip][placement="right-bottom"]::before {
|
||||
bottom: 10px;
|
||||
top: auto;
|
||||
transform: translate(0, 0) rotateZ(90deg);
|
||||
}
|
||||
|
||||
/*----下----*/
|
||||
.triangle-placement-bottom, [tooltip][placement="bottom"]::before, .triangle-placement-bottom-left, [tooltip][placement="bottom-left"]::before, .triangle-placement-bottom-right, [tooltip][placement="bottom-right"]::before {
|
||||
top: calc(100% + 5px);
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0) rotateZ(180deg);
|
||||
}
|
||||
|
||||
.triangle-placement-bottom-left, [tooltip][placement="bottom-left"]::before {
|
||||
transform: translate(0, 0) rotateZ(180deg);
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.triangle-placement-bottom-right, [tooltip][placement="bottom-right"]::before {
|
||||
right: 10px;
|
||||
left: auto;
|
||||
}
|
||||
|
||||
/*----左----*/
|
||||
.triangle-placement-left, [tooltip][placement="left"]::before, .triangle-placement-left-top, [tooltip][placement="left-top"]::before, .triangle-placement-left-bottom, [tooltip][placement="left-bottom"]::before {
|
||||
right: calc(100% + 3px);
|
||||
top: 50%;
|
||||
transform: translate(0, -50%) rotateZ(270deg);
|
||||
}
|
||||
|
||||
.triangle-placement-left-top, [tooltip][placement="left-top"]::before {
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
.triangle-placement-left-bottom, [tooltip][placement="left-bottom"]::before {
|
||||
bottom: 10px;
|
||||
top: auto;
|
||||
transform: translate(0, 0) rotateZ(270deg);
|
||||
}
|
||||
|
||||
@keyframes anime-top {
|
||||
from {
|
||||
opacity: .5;
|
||||
bottom: 150%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes anime-bottom {
|
||||
from {
|
||||
opacity: .5;
|
||||
top: 150%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes anime-left {
|
||||
from {
|
||||
opacity: .5;
|
||||
right: 150%;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes anime-right {
|
||||
from {
|
||||
opacity: .5;
|
||||
left: 150%;
|
||||
}
|
||||
}
|
||||
|
||||
/* 移动端小屏幕样式 */
|
||||
@media screen and (max-width:768px){
|
||||
/* 首页 */
|
||||
|
1
static/qrcodejs/qrcode.min.js
vendored
Normal file
1
static/qrcodejs/qrcode.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
3709
static/sortablejs/Sortable.js
Normal file
3709
static/sortablejs/Sortable.js
Normal file
File diff suppressed because it is too large
Load Diff
221
static/sortablejs/test.html
Normal file
221
static/sortablejs/test.html
Normal file
@ -0,0 +1,221 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<title>layout 后台大布局 - Layui</title>
|
||||
<link rel="stylesheet" href="../layui/css/layui.css">
|
||||
<style>
|
||||
.row {
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-ms-flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.list-group {
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
padding-left: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.col {
|
||||
-ms-flex-preferred-size: 0;
|
||||
flex-basis: 0;
|
||||
-ms-flex-positive: 1;
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding-right: 15px;
|
||||
padding-left: 15px;
|
||||
}
|
||||
.list-group-item:first-child {
|
||||
border-top-left-radius: .25rem;
|
||||
border-top-right-radius: .25rem;
|
||||
}
|
||||
.list-group-item {
|
||||
position: relative;
|
||||
display: block;
|
||||
padding: .75rem 1.25rem;
|
||||
margin-bottom: -1px;
|
||||
background-color: #fff;
|
||||
border: 1px solid rgba(0,0,0,.125);
|
||||
}
|
||||
.list-group-item:first-child {
|
||||
border-top-left-radius: 0.25rem;
|
||||
border-top-right-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.list-group-item:last-child {
|
||||
margin-bottom: 0;
|
||||
border-bottom-right-radius: 0.25rem;
|
||||
border-bottom-left-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.list-group-item:hover, .list-group-item:focus {
|
||||
z-index: 1;
|
||||
text-decoration: none;
|
||||
}
|
||||
.list-group-item.disabled, .list-group-item:disabled {
|
||||
color: #6c757d;
|
||||
pointer-events: none;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.list-group-item.active {
|
||||
z-index: 2;
|
||||
color: #fff;
|
||||
background-color: #007bff;
|
||||
border-color: #007bff;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body class="layui-layout-body">
|
||||
<div class="layui-layout layui-layout-admin">
|
||||
<div class="layui-header">
|
||||
<div class="layui-logo">layui 后台布局</div>
|
||||
<!-- 头部区域(可配合layui已有的水平导航) -->
|
||||
<ul class="layui-nav layui-layout-left">
|
||||
<li class="layui-nav-item"><a href="">控制台</a></li>
|
||||
<li class="layui-nav-item"><a href="">商品管理</a></li>
|
||||
<li class="layui-nav-item"><a href="">用户</a></li>
|
||||
<li class="layui-nav-item">
|
||||
<a href="javascript:;">其它系统</a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd><a href="">邮件管理</a></dd>
|
||||
<dd><a href="">消息管理</a></dd>
|
||||
<dd><a href="">授权管理</a></dd>
|
||||
</dl>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="layui-nav layui-layout-right">
|
||||
<li class="layui-nav-item">
|
||||
<a href="javascript:;">
|
||||
<img src="http://t.cn/RCzsdCq" class="layui-nav-img">
|
||||
贤心
|
||||
</a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd><a href="">基本资料</a></dd>
|
||||
<dd><a href="">安全设置</a></dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li class="layui-nav-item"><a href="">退了</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="layui-side layui-bg-black">
|
||||
<div class="layui-side-scroll">
|
||||
<!-- 左侧导航区域(可配合layui已有的垂直导航) -->
|
||||
<ul class="layui-nav layui-nav-tree" lay-filter="test">
|
||||
<li class="layui-nav-item layui-nav-itemed">
|
||||
<a class="" href="javascript:;">所有商品</a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd><a href="javascript:;">列表一</a></dd>
|
||||
<dd><a href="javascript:;">列表二</a></dd>
|
||||
<dd><a href="javascript:;">列表三</a></dd>
|
||||
<dd><a href="">超链接</a></dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li class="layui-nav-item">
|
||||
<a href="javascript:;">解决方案</a>
|
||||
<dl class="layui-nav-child">
|
||||
<dd><a href="javascript:;">列表一</a></dd>
|
||||
<dd><a href="javascript:;">列表二</a></dd>
|
||||
<dd><a href="">超链接</a></dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li class="layui-nav-item"><a href="">云市场</a></li>
|
||||
<li class="layui-nav-item"><a href="">发布商品</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-body">
|
||||
<!-- 内容主体区域 -->
|
||||
<div style="padding: 15px;">
|
||||
<div class="layui-row" style="margin-bottom: 10px;padding-left:15px;">
|
||||
<span class="layui-breadcrumb" lay-separator=">">
|
||||
<a href="{% url 'manage_project' %}">文集管理</a>
|
||||
<a><cite>导入文集</cite></a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="layui-card-header" style="margin-bottom: 10px;">
|
||||
<span style="font-size:18px;">导入文集到MrDoc</span>
|
||||
</div>
|
||||
<div class="layui-row" >
|
||||
<button class="layui-btn layui-btn-normal layui-btn-sm" id="upload-zip"><i class="layui-icon layui-icon-upload"></i>导入.Zip文件</button>
|
||||
</div>
|
||||
<div id="nested" class="row">
|
||||
<button onclick="getLevel()">aaa</button>
|
||||
<ul id="nestedDemo" class="list-group col nested-sortable">
|
||||
<li data-sortable-id="499" class="list-group-item" style="">万视电商数据助手脑图.<ul class="list-group nested-sortable"></ul></li>
|
||||
<li data-sortable-id="498" class="list-group-item" style="">《读懂一本书》思维导图.<ul class="list-group nested-sortable"></ul></li>
|
||||
<li data-sortable-id="500" class="list-group-item" style="">六类群体可得到慈善组织、红十字会优先帮扶_滚动新闻_中国政府网.<ul class="list-group nested-sortable"></ul></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="layui-footer">
|
||||
<!-- 底部固定区域 -->
|
||||
© layui.com - 底部固定区域
|
||||
</div>
|
||||
</div>
|
||||
<script src="../jquery/3.1.1/jquery.min.js"></script>
|
||||
<script src="../layui/layui.all.js"></script>
|
||||
<script src="./Sortable.js"></script>
|
||||
<script>
|
||||
// Nested demo
|
||||
var nestedSortables = [].slice.call(document.querySelectorAll('.nested-sortable'));
|
||||
|
||||
// Loop through each nested sortable element
|
||||
for (var i = 0; i < nestedSortables.length; i++) {
|
||||
new Sortable(nestedSortables[i], {
|
||||
group: {
|
||||
name:'nested',
|
||||
pull: function(event) {
|
||||
//console.log(event);
|
||||
var deep = event.el.parentNode.parentNode.parentNode.parentNode.className
|
||||
// console.log(deep)
|
||||
// please get deep
|
||||
// console.log(deep)
|
||||
if(deep == 'list-group nested-sortable') return false;
|
||||
return true;
|
||||
},
|
||||
},
|
||||
animation: 150,
|
||||
fallbackOnBody: true,
|
||||
invertSwap:true,
|
||||
swapThreshold: 0.65,
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
const nestedQuery = '.nested-sortable';
|
||||
const identifier = 'sortableId';
|
||||
const root = document.getElementById('nestedDemo');
|
||||
function serialize(sortable) {
|
||||
var serialized = [];
|
||||
var children = [].slice.call(sortable.children);
|
||||
for (var i in children) {
|
||||
var nested = children[i].querySelector(nestedQuery);
|
||||
serialized.push({
|
||||
id: children[i].dataset[identifier],
|
||||
children: nested ? serialize(nested) : []
|
||||
});
|
||||
}
|
||||
return serialized
|
||||
}
|
||||
|
||||
console.log(serialize(root))
|
||||
function getLevel(){
|
||||
console.log(serialize(root))
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -7,6 +7,7 @@
|
||||
<meta http-equiv="Cache-Control" content="no-transform" />
|
||||
<meta http-equiv="Cache-Control" content="no-siteapp" />
|
||||
<meta http-equiv="Cache-Control" content="max-age=7200" />
|
||||
<meta name="referrer" content="no-referrer">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<meta name="keywords" content="{% block keyword %}{% endblock %}mrdoc"/>
|
||||
<meta name="description" content="{% block description %}{% endblock %}" />
|
||||
@ -104,6 +105,13 @@
|
||||
.CodeMirror-linenumber{
|
||||
width: auto !important;
|
||||
}
|
||||
/* layui 折叠面板 边框颜色 - 用在左侧文集结构 */
|
||||
.layui-badge-rim, .layui-colla-content, .layui-colla-item, .layui-collapse, .layui-elem-field, .layui-form-pane .layui-form-item[pane], .layui-form-pane .layui-form-label, .layui-input, .layui-layedit, .layui-layedit-tool, .layui-quote-nm, .layui-select, .layui-tab-bar, .layui-tab-card, .layui-tab-title, .layui-tab-title .layui-this:after, .layui-textarea{
|
||||
border-color: #f8f8f8;
|
||||
}
|
||||
.layui-colla-content{
|
||||
padding: 0px;
|
||||
}
|
||||
</style>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
|
||||
@ -117,6 +125,7 @@
|
||||
<div class="doc-summary">
|
||||
<div class="project-title"><i class="fa fa-edit"></i> MrDoc文档编辑器<br>
|
||||
<span style="font-size: 14px;">你正在:{% block editor_type %}{% endblock %}</span>
|
||||
<span class="layui-badge layui-bg-cyan" id="wordcount">0</span>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
@ -245,7 +254,7 @@
|
||||
"undo", "redo", "|",
|
||||
"h1", "bold", "del", "italic", "quote","kaiSpan",
|
||||
"list-ul", "list-ol", "hr", "link", "reference-link",
|
||||
"mindmap","echart","imgUpload", "attachment" ,"code", "code-block", "htmltable",
|
||||
"mindmap","echart","imgUpload", "attachment" ,"multimedia","code", "code-block", "htmltable",
|
||||
"emoji", "html-entities", "pagebreak",
|
||||
"watch", "preview",
|
||||
"help"
|
||||
@ -261,7 +270,8 @@
|
||||
attachment:'fa-upload',
|
||||
htmltable:'fa-table',
|
||||
mindmap:'fa-sitemap',
|
||||
echart:'fa-bar-chart'
|
||||
echart:'fa-bar-chart',
|
||||
multimedia:'fa-youtube-play',
|
||||
},
|
||||
//设置自定义工具栏按钮的事件
|
||||
toolbarHandlers : {
|
||||
@ -284,7 +294,7 @@
|
||||
// this == 当前editormd实例
|
||||
//console.log("testIcon =>", this, cm, icon, cursor, selection);
|
||||
},
|
||||
// 点击工具栏图片图标的响应函数 - 上传图片和选择图片
|
||||
// 上传图片和选择图片
|
||||
imgUpload : function(cm,icon,cursor,selection){
|
||||
layer.ready(function(){
|
||||
element.init();
|
||||
@ -297,7 +307,7 @@
|
||||
content:$('#upload-img'),
|
||||
})
|
||||
},
|
||||
//点击工具栏文件按钮的响应函数 - 上传和选择附件
|
||||
// 上传和选择附件
|
||||
attachment : function(cm,icon,cursor,selection){
|
||||
layer.ready(function(){
|
||||
element.init();
|
||||
@ -339,7 +349,7 @@
|
||||
}
|
||||
})
|
||||
},
|
||||
//点击工具栏表格按钮的响应函数 - 添加表格
|
||||
// 添加表格
|
||||
htmltable:function(cm,icon,cursor,selection){
|
||||
layer.ready(function(){
|
||||
element.init();
|
||||
@ -388,11 +398,22 @@
|
||||
cm.setCursor(cursor.line+1, cursor.ch);
|
||||
}
|
||||
},
|
||||
// 添加echart图
|
||||
echart:function(cm,icon,cursor,selection){
|
||||
cm.replaceSelection('```echart\n' + selection + "\n```");
|
||||
if(selection === "") {
|
||||
cm.setCursor(cursor.line+1, cursor.ch);
|
||||
}
|
||||
},
|
||||
// 添加音视频
|
||||
multimedia:function(){
|
||||
layer.open({
|
||||
type:'1',
|
||||
title:'添加音视频外链',
|
||||
area:['800px','600px'],
|
||||
id:'insertMultiMedia',//配置ID,
|
||||
content:$('#insertMultimedia'),
|
||||
})
|
||||
}
|
||||
},
|
||||
//设置语言
|
||||
@ -404,6 +425,7 @@
|
||||
htmltable:"添加表格",
|
||||
mindmap:"添加思维导图",
|
||||
echart:"添加Echarts图表",
|
||||
multimedia:"添加音频、视频",
|
||||
}
|
||||
},
|
||||
//配置项
|
||||
@ -426,12 +448,17 @@
|
||||
imageUploadURL : "{% url 'upload_doc_img' %}",
|
||||
onchange:function(){
|
||||
md_changed = true;
|
||||
//console.log("字符数:",this.getMarkdown().length)
|
||||
// console.log("字符数:",this.getMarkdown().length)
|
||||
var wcnt = this.getMarkdown().length;
|
||||
$("#wordcount").text(wcnt);
|
||||
},
|
||||
onload : function() {
|
||||
// this.insertValue(" ")
|
||||
var wcnt = this.getMarkdown().length;
|
||||
$("#wordcount").text(wcnt);
|
||||
}
|
||||
});
|
||||
|
||||
//粘贴上传图片
|
||||
$("#editor-md").on('paste', function (ev) {
|
||||
var data = ev.clipboardData;
|
||||
@ -518,12 +545,18 @@
|
||||
})
|
||||
}
|
||||
});
|
||||
//插入选择的图片到编辑器
|
||||
// 插入选择的图片到编辑器
|
||||
insertImg = function(e){
|
||||
console.log(e.src);
|
||||
editor.insertValue("\n");
|
||||
};
|
||||
//切换图片分组
|
||||
// 按钮点击插入输入框图片链接
|
||||
insertImgUrl = function(){
|
||||
editor.insertValue("\n.val() + ")");
|
||||
$("#img_url_input").val("")
|
||||
layer.closeAll();
|
||||
};
|
||||
// 切换图片分组
|
||||
switchImgGroup = function(e){
|
||||
layer.load(1);
|
||||
$.post("{% url 'manage_image' %}", {
|
||||
@ -557,11 +590,25 @@
|
||||
}
|
||||
})
|
||||
};
|
||||
//插入选择的附件到编辑器
|
||||
// 插入选择的附件到编辑器
|
||||
insertAttach = function(e){
|
||||
editor.insertValue("\n[【附件】"+ $(e).data('name') + "](/media/" + $(e).data('path') + ")");
|
||||
layer.closeAll();
|
||||
}
|
||||
// 插入音视频到编辑器
|
||||
insertMultimedia = function(e){
|
||||
if(e === 'audio'){
|
||||
editor.insertValue("\n.val() + ")");
|
||||
}else if(e === 'video'){
|
||||
editor.insertValue("\n.val() + ")");
|
||||
}else if(e === 'video_iframe'){
|
||||
editor.insertValue("\n.val() + ")");
|
||||
}
|
||||
$("#audio_input").val('')
|
||||
$("#video_input").val('')
|
||||
$("#video_iframe_input").val('')
|
||||
layer.closeAll();
|
||||
}
|
||||
</script>
|
||||
{% block custom_script %}
|
||||
{% endblock %}
|
||||
@ -577,7 +624,16 @@
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<button class="layui-btn layui-btn-normal layui-btn-fluid" id="upload_img"><i class="layui-icon layui-icon-upload"></i> 点击上传图片</button>
|
||||
<div class="layui-row">
|
||||
<button class="layui-btn layui-btn-normal layui-btn-fluid" id="upload_img"><i class="layui-icon layui-icon-upload"></i> 点击上传图片</button>
|
||||
</div>
|
||||
<fieldset class="layui-elem-field layui-field-title" style="text-align: center;">
|
||||
<legend style="font-size: 12px;">或 插入外链图片链接</legend>
|
||||
</fieldset>
|
||||
<div class="layui-row" style="margin-top: 10px;">
|
||||
<input type="text" class="layui-input" placeholder="输入图片URL" id="img_url_input" style="margin-bottom: 5px;"/>
|
||||
<button type="button" class="layui-btn layui-btn-primary" onclick="insertImgUrl()">插入图片链接</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="layui-row" id="select-img-group">
|
||||
@ -588,6 +644,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 选择和上传附件div -->
|
||||
<div id="upload-attach" style="display:none;margin:20px;">
|
||||
<span>* 仅支持.zip格式的压缩文件作为附件,文件大小不超过50Mb</span>
|
||||
@ -607,6 +664,7 @@
|
||||
</table>
|
||||
<div id="select-attach-page"></div>
|
||||
</div>
|
||||
|
||||
<!-- 添加表格div -->
|
||||
<div id="layer-table" style="display: none;margin: 10px;">
|
||||
<div class="layui-tab" lay-filter="table-tab" id="insert-table-div">
|
||||
@ -641,6 +699,38 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 添加音视频div -->
|
||||
<div id="insertMultimedia" style="display: none;margin:10px;">
|
||||
<div class="layui-row">
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>插入音频链接</legend>
|
||||
<div class="layui-field-box">
|
||||
<input class="layui-input" type="url" id="audio_input" placeholder="填入音频文件链接,支持文件后缀格式为mp3、wav、flac、m4a" style="margin-bottom: 5px;">
|
||||
<button type="button" class="layui-btn layui-btn-sm layui-btn-normal" onclick="insertMultimedia('audio')"><i class="fa fa-music"></i> 插入音频</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="layui-row">
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>插入视频链接</legend>
|
||||
<div class="layui-field-box">
|
||||
<input class="layui-input" type="url" id="video_input" placeholder="填入视频文件链接,支持文件后缀格式为mp4、m4v、ogg、ogv、webm" style="margin-bottom: 5px;">
|
||||
<button type="button" class="layui-btn layui-btn-sm layui-btn-normal" onclick="insertMultimedia('video')"><i class="fa fa-video-camera"></i> 插入视频</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="layui-row">
|
||||
<fieldset class="layui-elem-field">
|
||||
<legend>插入视频网站链接</legend>
|
||||
<div class="layui-field-box">
|
||||
<input class="layui-input" type="url" id="video_iframe_input" placeholder="填入视频网站视频播放页链接,支持YouTube、优酷、QQ视频、Facebook、哔哩哔哩、TED网站" style="margin-bottom: 5px;">
|
||||
<button type="button" class="layui-btn layui-btn-sm layui-btn-normal" onclick="insertMultimedia('video_iframe')"><i class="fa fa-youtube-play"></i> 插入视频网站视频</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
//按钮选择上传图片
|
||||
var upload = layui.upload;
|
||||
@ -691,6 +781,7 @@
|
||||
field:'attachment_upload',
|
||||
size: 51200, //最大允许上传的文件大小
|
||||
})
|
||||
|
||||
//修改预览div中a标签链接新窗口打开
|
||||
$('div.editormd-preview').on('click','a',function(e){
|
||||
e.target.target = '_blank';
|
||||
|
@ -17,32 +17,18 @@
|
||||
|
||||
|
||||
{% block left_opera %}
|
||||
<div class="layui-form" style="padding: 10px;">
|
||||
<div class="layui-form" style="padding: 0 10px 10px 10px;">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12" style="margin-bottom: 10px;">
|
||||
<label class="doc-form-label" style="margin-right:0px;">
|
||||
<button class="layui-btn layui-btn-normal layui-btn-sm" id="sel-doctemp" title="插入模板内容">
|
||||
<i class="fa fa-clipboard"></i> 模板
|
||||
<div class="layui-btn-container" style="margin-bottom: 0px;">
|
||||
<button class="layui-btn layui-btn-primary layui-btn-sm mrdoc-btn-default" id="sel-doctemp" title="插入模板内容">
|
||||
<i class="fa fa-clipboard"></i> 选择模板
|
||||
</button>
|
||||
</label>
|
||||
|
||||
<label class="doc-form-label" style="margin-right:0px;">
|
||||
<input type="file" id="insert-local-file" onchange="insertLocalFile(this)" style="display:none;">
|
||||
<button class="layui-btn layui-btn-normal layui-btn-sm" id="sel-local" onclick="selectLocalFile()" title="插入本地文本文件内容">
|
||||
<i class="fa fa-clipboard"></i> 文本
|
||||
<button class="layui-btn layui-btn-primary layui-btn-sm mrdoc-btn-default" id="sel-local" onclick="selectLocalFile()" title="插入本地文本文件内容">
|
||||
<i class="fa fa-upload"></i> 导入文本
|
||||
</button>
|
||||
</label>
|
||||
|
||||
<label class="doc-form-label">
|
||||
<button class="layui-btn layui-btn-normal layui-btn-sm" onclick="saveDoc()" title="保存当前内容为草稿文档">
|
||||
<i class="fa fa-save"></i> 保存
|
||||
</button>
|
||||
</label>
|
||||
<label class="doc-form-label">
|
||||
<button class="layui-btn layui-btn-normal layui-btn-sm" onclick="createDoc()" id="create_doc" title="发布当前内容">
|
||||
<i class="fa fa-save"></i> 发布
|
||||
</button>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="layui-col-md12" style="margin-bottom: 10px;">
|
||||
@ -79,15 +65,36 @@
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12" style="margin-bottom: 10px;">
|
||||
<span>点击文档树选择上级(可选)或</span>
|
||||
<button class="layui-btn layui-btn-xs layui-btn-normal" id="clearParentDoc">不设上级</button>
|
||||
<button class="layui-btn layui-btn-xs layui-btn-normal" id="clearParentDoc">取消上级</button>
|
||||
<input type="text" id="parent-doc" hidden>
|
||||
</div>
|
||||
<div class="layui-col-md12">
|
||||
<input type="number" class="layui-input" placeholder="输入文档排序值,默认99" id="sort">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-collapse" style="margin-top: 10px;margin-bottom: 10px;">
|
||||
<div class="layui-colla-item">
|
||||
<h2 class="layui-colla-title">文档结构树</h2>
|
||||
<div class="layui-colla-content layui-show" style="max-height: 400px;overflow: hidden;overflow-y: scroll;overflow-x: scroll;">
|
||||
<div id="doc-tree"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="layui-row" style="margin-bottom: 10px;">
|
||||
<button class="layui-btn layui-btn-primary layui-btn-fluid mrdoc-btn-default" onclick="saveDoc()" title="保存当前内容为草稿文档">
|
||||
<i class="fa fa-save"></i> 保存文档为草稿
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="layui-row">
|
||||
<button class="layui-btn layui-btn-normal layui-btn-fluid" onclick="createDoc()" id="create_doc" title="发布当前内容">
|
||||
<i class="fa fa-save"></i> 发布文档
|
||||
</button>
|
||||
</div>
|
||||
<div class="layui-col-md12" id="doc-tree"></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@ -169,7 +176,7 @@
|
||||
var $me = $(this)
|
||||
if($me.data('id') == obj.data.id){
|
||||
// console.log('点击了')
|
||||
layer.msg("选择了上级文档:"+obj.data.title)
|
||||
layer.msg("你选择了上级文档:"+obj.data.title)
|
||||
$me.find('span.layui-tree-txt').first().addClass('selected-parent-doc')
|
||||
}else{
|
||||
$me.find('span.layui-tree-txt').first().removeClass('selected-parent-doc')
|
||||
@ -300,11 +307,11 @@
|
||||
//清除所选上级文档
|
||||
$("#clearParentDoc").click(function(){
|
||||
$('#parent-doc').val("");
|
||||
|
||||
$("span.layui-tree-txt").each(function(i){
|
||||
var $me = $(this)
|
||||
$me.removeClass('selected-parent-doc')
|
||||
});
|
||||
layer.msg("你取消了当前文档的上级文档")
|
||||
});
|
||||
//插入模板
|
||||
insertTemp = function(doctemp_id){
|
||||
|
@ -52,8 +52,8 @@
|
||||
|
||||
{% block doc_previous_next %}
|
||||
{% load doc_filter %}
|
||||
<div class="layui-row" style="margin-top: 10px;padding:10px;display:flex;justify-content:space-around;border-top: 1px #e6e6e6 solid;">
|
||||
<hr>
|
||||
<div class="layui-row" style="margin-top: 10px;padding:10px;display:flex;justify-content:space-around;">
|
||||
<!-- <hr> -->
|
||||
<div>
|
||||
{% if doc.id|get_doc_previous == None %}
|
||||
<button class="layui-btn layui-btn-disabled layui-btn-sm layui-btn-radius"><i class="layui-icon layui-icon-prev "></i>上一篇</button>
|
||||
|
@ -7,6 +7,7 @@
|
||||
<meta http-equiv="Cache-Control" content="no-transform" />
|
||||
<meta http-equiv="Cache-Control" content="no-siteapp" />
|
||||
<meta http-equiv="Cache-Control" content="max-age=7200" />
|
||||
<meta name="referrer" content="no-referrer">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<meta name="keywords" content="{% block keyword %}{% endblock %}mrdoc"/>
|
||||
<meta name="description" content="{% block description %}{% endblock %}" />
|
||||
@ -14,7 +15,6 @@
|
||||
<link href="{% static 'layui/css/layui.css' %}?version={{mrdoc_version}}" rel="stylesheet">
|
||||
<link rel="stylesheet" href="{% static 'editor.md/css/editormd.css' %}?version={{mrdoc_version}}" />
|
||||
<link rel="stylesheet" href="{% static 'katex/katex.min.css' %}?version={{mrdoc_version}}" />
|
||||
<link rel="stylesheet" href="{% static 'share.js/css/share.min.css' %}?version={{mrdoc_version}}" />
|
||||
<link href="{% static 'viewerjs/viewer.css' %}?version={{mrdoc_version}}" rel="stylesheet">
|
||||
<link rel="icon" href="{% static 'favicon_16.png' %}"/>
|
||||
<link href="{% static 'mrdoc.css' %}?version={{mrdoc_version}}" rel="stylesheet">
|
||||
@ -79,6 +79,19 @@
|
||||
.markdown-body h6{
|
||||
font-size: .85em;
|
||||
}
|
||||
#url_qrcode img{
|
||||
margin: auto;
|
||||
}
|
||||
#share{
|
||||
background-color: #333;
|
||||
}
|
||||
/* layui弹出框颜色 */
|
||||
.layui-tab-brief>.layui-tab-more li.layui-this:after, .layui-tab-brief>.layui-tab-title .layui-this:after{
|
||||
border-bottom: 2px solid #333;
|
||||
}
|
||||
.layui-tab-brief>.layui-tab-title .layui-this{
|
||||
color: #333;
|
||||
}
|
||||
</style>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
|
||||
@ -195,6 +208,11 @@
|
||||
</div>
|
||||
<!-- 正文结束 -->
|
||||
</div>
|
||||
<hr>
|
||||
<!-- 分享栏 -->
|
||||
<button id="share" class="layui-btn layui-btn-radius layui-btn-xs">
|
||||
<i class="fa fa-share-alt"></i> 分享
|
||||
</button>
|
||||
|
||||
<!-- 广告代码开始 -->
|
||||
{% if debug %}
|
||||
@ -208,10 +226,6 @@
|
||||
<!-- 广告代码结束 -->
|
||||
|
||||
{% block doc_previous_next %}{% endblock %}
|
||||
<!-- 社交分享 -->
|
||||
<div class="share-div" style="margin-top: 10px;padding:10px;text-align: center;background-color: #fafafa">
|
||||
分享到:<span class="social-share"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@ -258,7 +272,7 @@
|
||||
|
||||
<!-- <script src="{% static 'editor.md/editormd.min.js' %}"></script> -->
|
||||
<script src="{% static 'editor.md/editormd.js' %}?version={{mrdoc_version}}"></script>
|
||||
<script src="{% static 'share.js/js/social-share.min.js' %}"></script>
|
||||
<script src="{% static 'qrcodejs/qrcode.min.js' %}"></script>
|
||||
|
||||
<!-- 解析Markdown -->
|
||||
<script>
|
||||
@ -266,7 +280,6 @@
|
||||
data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
|
||||
});
|
||||
//解析Markdown为HTML
|
||||
// layer.load(1);
|
||||
editormd.markdownToHTML("content", {
|
||||
htmlDecode : "style,script,iframe",
|
||||
emoji : true, //emoji表情
|
||||
@ -281,6 +294,18 @@
|
||||
atLink : false,//禁用@链接
|
||||
|
||||
});
|
||||
// 显示分享弹出框
|
||||
$("#share").click(function(r){
|
||||
var layer = layui.layer;
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: false,
|
||||
closeBtn: 0,
|
||||
area: ['350px','350px'],
|
||||
shadeClose: true,
|
||||
content: $('#share_div')
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- 生成文集目录大纲 -->
|
||||
@ -290,18 +315,6 @@
|
||||
$.post("{% url 'get_pro_doc_tree' %}",{'pro_id':'{{project.id}}'},function(r){
|
||||
$("#loading-project-toc").hide();
|
||||
if(r.status){
|
||||
// var doc_tree = tree.render({
|
||||
// elem:"#project-toc",
|
||||
// id:'projectToc',
|
||||
// // showCheckbox:true,
|
||||
// onlyIconControl:true,
|
||||
// isJump:true,
|
||||
// data:r.data,
|
||||
// text: {
|
||||
// defaultNodeName: '未命名' //节点默认名称
|
||||
// ,none: '文集暂无文档' //数据为空时的提示文本
|
||||
// },
|
||||
// });
|
||||
var toc_str = ""
|
||||
layui.each(r.data,function(index,item){
|
||||
toc_str += "<li>"
|
||||
@ -401,6 +414,8 @@
|
||||
$(".toTop").click(function() {
|
||||
$(document).scrollTop(0);
|
||||
});
|
||||
// 生成当前网页链接
|
||||
$("input[name=current_url]").val(document.URL)
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -465,9 +480,27 @@
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- 展开收起左边目录 -->
|
||||
<!-- 分享选项卡模板 -->
|
||||
<div id="share_div" style="display: none;">
|
||||
<div class="layui-tab layui-tab-brief" lay-filter="docDemoTabBrief">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">微信扫一扫</li>
|
||||
<li>复制链接</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content" style="height: 100px;">
|
||||
<div class="layui-tab-item layui-show" align='center'>
|
||||
<p style="font-weight: 700;margin-bottom: 10px;">手机扫一扫进行分享</p>
|
||||
<div id="url_qrcode"></div>
|
||||
</div>
|
||||
<div class="layui-tab-item" align='center'>
|
||||
<input type="text" id="copy_crt_url" name="current_url" class="layui-input" /><br>
|
||||
<button class="layui-btn layui-btn-radius layui-btn-xs" style="background-color: #333;" onclick="copyUrl();">复制链接</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
// 展开收起左边目录
|
||||
$(function(){
|
||||
// $(".switch-toc").click(SwitchToc);
|
||||
$("body").on('click','.switch-toc',SwitchToc)
|
||||
@ -478,10 +511,8 @@
|
||||
$(this).parent().next("ul").toggleClass("toc-close"); //切换展开收起样式
|
||||
$(this).toggleClass("fa-chevron-left fa-chevron-down");//切换图标
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- 展开\收起文档树 -->
|
||||
<script>
|
||||
// 展开文档树
|
||||
function openDocTree(){
|
||||
$("nav ul.summary ul").each(function(obj){
|
||||
console.log(obj,this)
|
||||
@ -490,14 +521,31 @@
|
||||
})
|
||||
|
||||
};
|
||||
// 收起文档树
|
||||
function closeDocTree(){
|
||||
$("nav ul.summary ul").each(function(obj){
|
||||
console.log(obj,this)
|
||||
$(this).addClass("toc-close")
|
||||
$(this).prev().children('i').toggleClass("fa-chevron-left fa-chevron-down");//切换图标
|
||||
})
|
||||
|
||||
};
|
||||
// 文档分享 - 复制链接
|
||||
copyUrl = function(){
|
||||
var crt_url_val = document.getElementById("copy_crt_url");
|
||||
crt_url_val.select();
|
||||
window.clipb
|
||||
document.execCommand("Copy");
|
||||
layer.msg("链接复制成功!")
|
||||
}
|
||||
// 生成二维码
|
||||
var qrcode = new QRCode("url_qrcode", {
|
||||
text: document.URL,
|
||||
width: 200,
|
||||
height: 200,
|
||||
colorDark : "#000000",
|
||||
colorLight : "#ffffff",
|
||||
correctLevel : QRCode.CorrectLevel.H
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- 统计代码开始 -->
|
||||
|
@ -1,7 +1,7 @@
|
||||
<div class="layui-footer" style="border-top: 1px #e6e6e6 solid;text-align:center;margin-top:10px;width:100%;">
|
||||
<div style="margin-top:10px;">
|
||||
© <a href="/">MrDoc 2019-2020</a> |
|
||||
<span class="layui-hide-xs">基于<a href="https://www.djangoproject.com/" target="_blank">Django</a> | </span>
|
||||
<!-- <span class="layui-hide-xs">基于<a href="https://www.djangoproject.com/" target="_blank">Django</a> | </span> -->
|
||||
<a href="https://zmister.com" target="_blank">州的先生</a>出品 |
|
||||
<a href="{% url 'sitemap' %}" target="_blank">网站地图</a>
|
||||
</div>
|
||||
|
@ -7,8 +7,9 @@
|
||||
<title>{% block title %}{% endblock %} - 个人中心 - 觅道文档MrDoc</title>
|
||||
<link href="{% static 'layui/css/layui.css' %}?version={{mrdoc_version}}" rel="stylesheet">
|
||||
<link href="{% static 'mrdoc-admin.css' %}?version={{mrdoc_version}}" rel="stylesheet">
|
||||
<link href="{% static 'viewerjs/viewer.css' %}?version={{mrdoc_version}}" rel="stylesheet">
|
||||
<link rel="icon" href="{% static 'favicon_16.png' %}"/>
|
||||
{% block custom_link %}
|
||||
{% endblock %}
|
||||
<style>
|
||||
.layui-btn a{
|
||||
color:white;
|
||||
@ -116,12 +117,13 @@
|
||||
<div style="padding: 15px;">{% block content %}{% endblock %}</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-footer" style="text-align:center;">
|
||||
<div class="layui-footer" style="text-align:center;font-size: 12px;">
|
||||
<!-- 底部固定区域 -->
|
||||
© <a href="https://gitee.com/zmister/MrDoc" target="_blank">MrDoc 2019-2020</a> -
|
||||
当前版本:<a href="https://gitee.com/zmister/MrDoc/tree/{{mrdoc_version}}/" target="_blank">{{mrdoc_version}}</a> -
|
||||
<a href="https://github.com/zmister2016/MrDoc" target="_blank">GitHub</a> -
|
||||
<a href="https://gitee.com/zmister/MrDoc" target="_blank">码云</a>
|
||||
<a href="https://gitee.com/zmister/MrDoc" target="_blank">码云</a> -
|
||||
<a class="register-link" id="dashang" href="javascript:void(0);">打赏作者</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -145,8 +147,47 @@
|
||||
$.ajaxSetup({
|
||||
data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
|
||||
});
|
||||
// 显示打赏图片
|
||||
$("#dashang").click(function(r){
|
||||
var layer = layui.layer;
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: false,
|
||||
closeBtn: 0,
|
||||
area: ['400px','400px'],
|
||||
shadeClose: true,
|
||||
content: $('#dashang_img')
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% block custom_script %}
|
||||
{% endblock %}
|
||||
</body>
|
||||
<!-- 打赏选项卡模板 -->
|
||||
<div id="dashang_img" style="display: none;">
|
||||
<div class="layui-tab layui-tab-brief" lay-filter="docDemoTabBrief">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">微信</li>
|
||||
<li>支付宝</li>
|
||||
<li>QQ支付</li>
|
||||
<li>PayPal</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content" style="height: 100px;">
|
||||
<div class="layui-tab-item layui-show" align='center'>
|
||||
<img src="{% static 'dashang/dashang_wx.jpg' %}" style="width: 300px;height: auto;" />
|
||||
</div>
|
||||
<div class="layui-tab-item" align='center'>
|
||||
<img src="{% static 'dashang/dashang_alipay.jpg' %}" style="width: 300px;height: auto;" />
|
||||
</div>
|
||||
<div class="layui-tab-item" align='center'>
|
||||
<img src="{% static 'dashang/dashang_qq.png' %}" style="width: 300px;height: auto;" />
|
||||
</div>
|
||||
<div class="layui-tab-item" align='center'>
|
||||
<a href="https://paypal.me/zmister" target="_blank">
|
||||
<img src="{% static 'dashang/dashang_paypal.png' %}" style="width: 280px;height: auto;" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</html>
|
@ -1,6 +1,11 @@
|
||||
{% extends 'app_doc/manage_base.html' %}
|
||||
{% load staticfiles %}
|
||||
{% block title %}图片素材管理{% endblock %}
|
||||
|
||||
{% block custom_link %}
|
||||
<link href="{% static 'viewerjs/viewer.css' %}?version={{mrdoc_version}}" rel="stylesheet">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="layui-card-header" style="margin-bottom: 10px;">
|
||||
<div class="layui-row">
|
||||
|
@ -17,6 +17,7 @@
|
||||
<button class="layui-btn layui-btn-normal layui-btn-sm" type="submit"><i class="layui-icon layui-icon-search" ></i>搜索</button>
|
||||
<button class="layui-btn layui-btn-normal layui-btn-sm" onclick="createProject()" type="button"><i class="layui-icon layui-icon-addition"></i>新建文集</button>
|
||||
<a class="layui-btn layui-btn-normal layui-btn-sm" href="{% url 'manage_pro_colla_self' %}"><i class="layui-icon layui-icon-group"></i>我协作的文集</a>
|
||||
<a class="layui-btn layui-btn-normal layui-btn-sm" href="{% url 'import_project' %}"><i class="layui-icon layui-icon-upload"></i>导入文集</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
249
template/app_doc/manage_project_import.html
Normal file
249
template/app_doc/manage_project_import.html
Normal file
@ -0,0 +1,249 @@
|
||||
{% extends 'app_doc/manage_base.html' %}
|
||||
{% load staticfiles %}
|
||||
{% block title %}导入文集{% endblock %}
|
||||
{% block content %}
|
||||
<div class="layui-row" style="margin-bottom: 10px;padding-left:15px;">
|
||||
<span class="layui-breadcrumb" lay-separator=">">
|
||||
<a href="{% url 'manage_project' %}">文集管理</a>
|
||||
<a><cite>导入文集</cite></a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="layui-card-header" style="margin-bottom: 10px;">
|
||||
<span style="font-size:18px;">导入文集到MrDoc</span>
|
||||
</div>
|
||||
<div class="layui-row" >
|
||||
<button class="layui-btn layui-btn-normal layui-btn-sm" id="upload-zip"><i class="layui-icon layui-icon-upload"></i>导入Markdown压缩包(.Zip)</button>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
{% block custom_script %}
|
||||
|
||||
<script>
|
||||
$.ajaxSetup({
|
||||
data: {csrfmiddlewaretoken: '{{ csrf_token }}' },
|
||||
});
|
||||
var upload = layui.upload;
|
||||
// 上传Zip文件
|
||||
var uploadZip = upload.render({
|
||||
elem: '#upload-zip', //绑定元素
|
||||
url: "{% url 'import_project' %}", //上传接口
|
||||
accept:'file',
|
||||
exts:'zip',
|
||||
data:{'type':'zip',csrfmiddlewaretoken: '{{ csrf_token }}'},
|
||||
field:'import_file',
|
||||
before:function(){
|
||||
layer.load(1);
|
||||
},
|
||||
done: function(res){
|
||||
//上传完毕回调
|
||||
layer.closeAll('loading'); //关闭loading
|
||||
// 遍历文集的文档
|
||||
layui.each(res.data,function(index,item){
|
||||
// console.log(index,item)
|
||||
var doc_ele = '<li data-sortable-id="'+ item[0] +'" class="list-group-item">'+item[1]+'<ul class="list-group nested-sortable"></ul></li>'
|
||||
$("#nestedDemo").append(doc_ele)
|
||||
});
|
||||
docSort();// 动态添加元素之后,调用一次
|
||||
// 打开排序弹出框
|
||||
var editor_import = layer.open({
|
||||
type:1,
|
||||
title:'编辑导入的文集',
|
||||
area:['700px','400px'],
|
||||
content:$("#import-project-sort"),
|
||||
btn:['保存文档','发布文档'],
|
||||
yes:function(index,layero){
|
||||
// 保存文档
|
||||
console.log(serialize(root))
|
||||
var sort_data = {
|
||||
'pid':res.id,
|
||||
'title':$('input[name="project-name"]').val(),
|
||||
'desc':$('input[name="project-desc"]').val(),
|
||||
'role':$(':radio[name="role"]:checked').val(),
|
||||
'sort_data':JSON.stringify(serialize(root)),
|
||||
'status':0,
|
||||
}
|
||||
console.log(sort_data)
|
||||
$.post('{% url "project_doc_sort" %}',sort_data,function(r){
|
||||
if(r.status){
|
||||
layer.msg("完成文集导入",function(){
|
||||
layer.close(index)
|
||||
window.location.href = "{% url 'manage_project' %}"
|
||||
})
|
||||
|
||||
}else{
|
||||
layer.msg("修改导入文集出错")
|
||||
}
|
||||
});
|
||||
},
|
||||
btn2:function(index,layero){
|
||||
// 发布文档
|
||||
console.log(serialize(root))
|
||||
var sort_data = {
|
||||
'pid':res.id,
|
||||
'title':$('input[name="project-name"]').val(),
|
||||
'desc':$('input[name="project-desc"]').val(),
|
||||
'role':$(':radio[name="role"]:checked').val(),
|
||||
'sort_data':JSON.stringify(serialize(root)),
|
||||
'status':1,
|
||||
}
|
||||
console.log(sort_data)
|
||||
$.post('{% url "project_doc_sort" %}',sort_data,function(r){
|
||||
if(r.status){
|
||||
layer.msg("完成文集导入",function(){
|
||||
layer.close(index)
|
||||
window.location.href = "{% url 'manage_project' %}"
|
||||
})
|
||||
}else{
|
||||
layer.msg("修改导入文集出错")
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
})
|
||||
|
||||
},
|
||||
error: function(){
|
||||
//请求异常回调
|
||||
layer.closeAll('loading'); //关闭loading
|
||||
layer.msg("文件上传出错")
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
<!-- 导入的文集文档排序模板div -->
|
||||
<style>
|
||||
.row {
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-ms-flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.list-group {
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
padding-left: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.col {
|
||||
-ms-flex-preferred-size: 0;
|
||||
flex-basis: 0;
|
||||
-ms-flex-positive: 1;
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding-right: 15px;
|
||||
padding-left: 15px;
|
||||
}
|
||||
.list-group-item:first-child {
|
||||
border-top-left-radius: .25rem;
|
||||
border-top-right-radius: .25rem;
|
||||
}
|
||||
.list-group-item {
|
||||
position: relative;
|
||||
display: block;
|
||||
padding: .75rem 1.25rem;
|
||||
margin-bottom: -1px;
|
||||
background-color: #fff;
|
||||
border: 1px solid rgba(0,0,0,.125);
|
||||
}
|
||||
.list-group-item:first-child {
|
||||
border-top-left-radius: 0.25rem;
|
||||
border-top-right-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.list-group-item:last-child {
|
||||
margin-bottom: 0;
|
||||
border-bottom-right-radius: 0.25rem;
|
||||
border-bottom-left-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.list-group-item:hover, .list-group-item:focus {
|
||||
z-index: 1;
|
||||
text-decoration: none;
|
||||
}
|
||||
.list-group-item.disabled, .list-group-item:disabled {
|
||||
color: #6c757d;
|
||||
pointer-events: none;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.list-group-item.active {
|
||||
z-index: 2;
|
||||
color: #fff;
|
||||
background-color: #007bff;
|
||||
border-color: #007bff;
|
||||
}
|
||||
|
||||
</style>
|
||||
<div id="import-project-sort" style="display: none;margin: 10px;" class="layui-form">
|
||||
<div class="layui-row" style="padding-left: 14px;padding-bottom: 10px;">
|
||||
<input class="layui-input" placeholder="请输入文集名称" name="project-name">
|
||||
</div>
|
||||
<div class="layui-row" style="padding-left: 14px;padding-bottom: 10px;">
|
||||
<input class="layui-input" placeholder="请输入文集简介" name="project-desc">
|
||||
</div>
|
||||
<div class="layui-row" style="">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label" style="width: auto;">文集状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="role" value="1" title="私密" checked>
|
||||
<input type="radio" name="role" value="0" title="公开">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-row" style="padding-left: 14px;padding-bottom: 10px;">文档拖拽排序</div>
|
||||
<div id="nested" class="row">
|
||||
<ul id="nestedDemo" class="list-group col nested-sortable"></ul>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 文档拖拽排序 -->
|
||||
<script src="{% static 'sortablejs/Sortable.js' %}"></script>
|
||||
<script>
|
||||
// 文档动态排序
|
||||
function docSort(){
|
||||
// Nested demo
|
||||
var nestedSortables = [].slice.call(document.querySelectorAll('.nested-sortable'));
|
||||
// Loop through each nested sortable element
|
||||
for (var i = 0; i < nestedSortables.length; i++) {
|
||||
new Sortable(nestedSortables[i], {
|
||||
group: {
|
||||
name:'docsort',
|
||||
pull: function(event) {
|
||||
var deep = event.el.parentNode.parentNode.parentNode.parentNode.className
|
||||
if(deep == 'list-group nested-sortable') return false;
|
||||
return true;
|
||||
},
|
||||
},
|
||||
animation: 150,
|
||||
fallbackOnBody: true,
|
||||
invertSwap:true,
|
||||
swapThreshold: 0.65,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const nestedQuery = '.nested-sortable';
|
||||
const identifier = 'sortableId';
|
||||
const root = document.getElementById('nestedDemo');
|
||||
function serialize(sortable) {
|
||||
var serialized = [];
|
||||
var children = [].slice.call(sortable.children);
|
||||
for (var i in children) {
|
||||
var nested = children[i].querySelector(nestedQuery);
|
||||
serialized.push({
|
||||
id: children[i].dataset[identifier],
|
||||
children: nested ? serialize(nested) : []
|
||||
});
|
||||
}
|
||||
return serialized
|
||||
}
|
||||
function getLevel(){
|
||||
console.log(serialize(root))
|
||||
}
|
||||
form.render();
|
||||
</script>
|
||||
{% endblock %}
|
@ -49,26 +49,15 @@
|
||||
|
||||
<div class="layui-col-md12" style="margin-bottom: 10px;">
|
||||
<label class="doc-form-label" style="margin-right:0px;">
|
||||
<button class="layui-btn layui-btn-normal layui-btn-sm" id="sel-doctemp" title="插入模板内容">
|
||||
<i class="fa fa-clipboard"></i> 模板
|
||||
<button class="layui-btn layui-btn-primary layui-btn-sm mrdoc-btn-default" id="sel-doctemp" title="插入文档模板">
|
||||
<i class="fa fa-clipboard"></i> 选择模板
|
||||
</button>
|
||||
</label>
|
||||
|
||||
<label class="doc-form-label" style="margin-right:0px;">
|
||||
<input type="file" id="insert-local-file" onchange="insertLocalFile(this)" style="display:none;">
|
||||
<button class="layui-btn layui-btn-normal layui-btn-sm" id="sel-local" onclick="selectLocalFile()" title="插入本地文本文件内容">
|
||||
<i class="fa fa-clipboard"></i> 文本
|
||||
</button>
|
||||
</label>
|
||||
|
||||
<label class="doc-form-label">
|
||||
<button class="layui-btn layui-btn-normal layui-btn-sm" onclick="saveDoc()" title="保存当前内容为草稿文档">
|
||||
<i class="fa fa-save"></i> 保存
|
||||
</button>
|
||||
</label>
|
||||
<label class="doc-form-label">
|
||||
<button class="layui-btn layui-btn-normal layui-btn-sm" onclick="createDoc()" id="create_doc" title="发布当前内容">
|
||||
<i class="fa fa-save"></i> 发布
|
||||
<button class="layui-btn layui-btn-primary layui-btn-sm mrdoc-btn-default" id="sel-local" onclick="selectLocalFile()" title="插入本地文本文件内容">
|
||||
<i class="fa fa-upload"></i> 导入文本
|
||||
</button>
|
||||
</label>
|
||||
</div>
|
||||
@ -84,23 +73,46 @@
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12" style="margin-bottom: 10px;">
|
||||
<span>点击文档树选择上级(可选)或</span>
|
||||
<button class="layui-btn layui-btn-xs layui-btn-normal" id="clearParentDoc">不设上级</button>
|
||||
<button class="layui-btn layui-btn-xs layui-btn-normal" id="clearParentDoc">取消上级</button>
|
||||
<input type="text" id="parent-doc" hidden>
|
||||
</div>
|
||||
<div class="layui-col-md12">
|
||||
<input type="number" class="layui-input" placeholder="输入文档排序值,默认99" id="sort" value="{{doc.sort}}">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="layui-col-md12" id="doc-tree"></div>
|
||||
</div>
|
||||
<div class="layui-row" style="margin-top: 20px;">
|
||||
<button class="layui-btn layui-btn-warm layui-btn-fluid" onclick="moveDoc()" title="复制或移动此文档到其他文集">复制/移动文档</button>
|
||||
</div>
|
||||
|
||||
<div class="layui-row" style="margin-top: 10px;">
|
||||
<button class="layui-btn layui-btn-danger layui-btn-fluid" onclick="delDoc()" title="删除此文档">删除文档</button>
|
||||
<div class="layui-collapse" style="margin-top: 10px;margin-bottom: 10px;">
|
||||
<div class="layui-colla-item">
|
||||
<h2 class="layui-colla-title">文档结构树</h2>
|
||||
<div class="layui-colla-content layui-show" style="max-height: 400px;overflow: hidden;overflow-y: scroll;overflow-x: scroll;">
|
||||
<div id="doc-tree"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
<div class="layui-row" style="margin-top: 10px;">
|
||||
<button class="layui-btn layui-btn-primary layui-btn-fluid mrdoc-btn-default" onclick="saveDoc()" title="保存当前内容为草稿文档">
|
||||
<i class="fa fa-save"></i> 保存为草稿
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="layui-row" style="margin-top: 10px;">
|
||||
<button class="layui-btn layui-btn-normal layui-btn-fluid" onclick="createDoc()" id="create_doc" title="发布当前内容">
|
||||
<i class="fa fa-save"></i> 发布文档
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="layui-row" style="margin-top: 10px;">
|
||||
<button class="layui-btn layui-btn-warm layui-btn-fluid" onclick="moveDoc()" title="复制或移动此文档到其他文集"><i class="fa fa-copy"></i> 复制/移动文档</button>
|
||||
</div>
|
||||
|
||||
<div class="layui-row" style="margin-top: 10px;">
|
||||
<button class="layui-btn layui-btn-danger layui-btn-fluid" onclick="delDoc()" title="删除此文档"><i class="fa fa-trash"></i> 删除文档</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
@ -126,7 +138,7 @@
|
||||
//获取文档数和上级文档信息
|
||||
$(function(){
|
||||
layer.load(1);
|
||||
var doc_parent_id = {{ doc.parent_doc }};
|
||||
var doc_parent_id = '{{ doc.parent_doc }}';
|
||||
$.post("{% url 'get_pro_doc_tree' %}",{'pro_id':$("#project").val()},function(r){
|
||||
if(r.status){
|
||||
layer.closeAll("loading");
|
||||
@ -138,12 +150,13 @@
|
||||
click: function(obj){
|
||||
if(obj.data.level != 3){
|
||||
console.log(obj.data.id,doc_parent_id)
|
||||
if(obj.data.id != {{ doc.id }} ){
|
||||
if(obj.data.id != '{{ doc.id }}' ){
|
||||
$('#parent-doc').val(obj.data.id);// 设置上级文档
|
||||
$("div.layui-tree-set").each(function(i){
|
||||
var $me = $(this)
|
||||
if($me.data('id') == obj.data.id){
|
||||
// console.log('点击了')
|
||||
layer.msg("你选择了上级文档:"+obj.data.title)
|
||||
$me.find('span.layui-tree-txt').first().addClass('selected-parent-doc')
|
||||
}else{
|
||||
$me.find('span.layui-tree-txt').first().removeClass('selected-parent-doc')
|
||||
@ -179,7 +192,7 @@
|
||||
$('button.layui-btn').addClass('layui-btn-disabled');
|
||||
layer.load(1);
|
||||
var data = {
|
||||
'doc_id':{{ doc.id }},
|
||||
'doc_id':'{{ doc.id }}',
|
||||
'project':$("#project").val(),
|
||||
'parent_doc':$("#parent-doc").val(),
|
||||
'doc_name':$("#doc-name").val(),
|
||||
@ -210,7 +223,7 @@
|
||||
$('button.layui-btn').addClass('layui-btn-disabled');
|
||||
layer.load(1);
|
||||
var data = {
|
||||
'doc_id':{{ doc.id }},
|
||||
'doc_id':'{{ doc.id }}',
|
||||
'project':$("#project").val(),
|
||||
'parent_doc':$("#parent-doc").val(),
|
||||
'doc_name':$("#doc-name").val(),
|
||||
@ -240,8 +253,8 @@
|
||||
layer.open({
|
||||
type: 1,
|
||||
id:'temp-div',
|
||||
content: $('#doctemp-list'),
|
||||
area:['530px','300px'],
|
||||
content: $('#doctemp-list'),
|
||||
area:['530px','400px'],
|
||||
});
|
||||
});
|
||||
//插入模板
|
||||
@ -261,6 +274,7 @@
|
||||
$("#doc-history").click(function(){
|
||||
layer.open({
|
||||
type: 1,
|
||||
title:'查看当前文档的历史版本',
|
||||
id:'history-div',
|
||||
content: $('#history-list'),
|
||||
area:['530px','300px'],
|
||||
@ -301,7 +315,7 @@
|
||||
yes:function (index,layero) {
|
||||
layer.load(1);
|
||||
data = {
|
||||
'doc_id':{{ doc.id }},
|
||||
'doc_id':'{{ doc.id }}',
|
||||
};
|
||||
$.post("{% url 'del_doc' %}",data,function(r){
|
||||
layer.closeAll('loading')
|
||||
@ -404,8 +418,8 @@
|
||||
<!-- 模板div块 -->
|
||||
<div class="doctemp-list" id="doctemp-list" style="display: none;width: 500px;">
|
||||
<div style="margin: 10px 0 0 10px;">
|
||||
<a class="layui-btn layui-btn-normal" href="{% url 'create_doctemp' %}" target="_blank">创建新模板</a>
|
||||
<a class="layui-btn layui-btn-normal" href="{% url 'manage_doctemp' %}" target="_blank">管理文档模板</a>
|
||||
<a class="layui-btn layui-btn-normal layui-btn-sm" href="{% url 'create_doctemp' %}" target="_blank">创建新模板</a>
|
||||
<a class="layui-btn layui-btn-normal layui-btn-sm" href="{% url 'manage_doctemp' %}" target="_blank">管理文档模板</a>
|
||||
</div>
|
||||
<table class="layui-table" style="margin: 10px;">
|
||||
<colgroup>
|
||||
@ -451,7 +465,7 @@
|
||||
<td>{{ history.create_time }}</td>
|
||||
<td>{{ history.create_user }}</td>
|
||||
<td>
|
||||
<a href="{% url 'diff_doc' history.doc.id history.id %}" target="_blank">查看差异</a>
|
||||
<a href="{% url 'diff_doc' history.doc.id history.id %}" class="layui-btn layui-btn-primary layui-btn-sm" target="_blank">查看版本差异</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="javascript:void(0);" class="layui-btn layui-btn-normal layui-btn-sm" onclick="insertHistory('{{history.doc.id}}','{{history.id}}');">恢复此版本</a>
|
||||
|
@ -44,7 +44,7 @@
|
||||
{% if enable_project_report %}
|
||||
<div class="layui-row">
|
||||
<h3>文集下载:</h3>
|
||||
<p>
|
||||
<p style="margin-bottom: 0px;">
|
||||
<span class="layui-breadcrumb" lay-separator="|">
|
||||
{% if allow_download %}
|
||||
{% if allow_download.allow_epub == 1 %}
|
||||
|
Loading…
Reference in New Issue
Block a user