更新前端文件
@@ -25,7 +25,8 @@ class Config extends Admin{
|
||||
*/
|
||||
public function group(ConfigModel $config){
|
||||
if ($this->request->isAjax()) {
|
||||
# code...
|
||||
$this->data['code'] = 1;
|
||||
return $this->data;
|
||||
}else{
|
||||
$this->data['id'] = $this->request->param('id', 1);
|
||||
$res = $config->where(array('status' => 1, 'group' => $this->data['id']))->field('id,name,title,extra,value,remark,type')->order('sort')->select();
|
||||
|
||||
@@ -26,6 +26,11 @@ class Index extends Admin{
|
||||
* @title 更新缓存
|
||||
*/
|
||||
public function clear(){
|
||||
if ($this->request->isAjax()) {
|
||||
# code...
|
||||
}else{
|
||||
return $this->data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,5 +8,5 @@ return [
|
||||
// Session初始化
|
||||
\think\middleware\SessionInit::class,
|
||||
// 页面Trace调试
|
||||
\think\middleware\TraceDebug::class,
|
||||
// \think\middleware\TraceDebug::class,
|
||||
];
|
||||
|
||||
@@ -26,7 +26,9 @@ class Admin {
|
||||
}
|
||||
|
||||
if ($request->isAjax()) {
|
||||
if (isset($this->data['config'])) {
|
||||
unset($this->data['config']);
|
||||
}
|
||||
return json($this->data);
|
||||
} else {
|
||||
return $response->data($this->fetch());
|
||||
@@ -47,8 +49,7 @@ class Admin {
|
||||
'__public__' => '/static/admin',
|
||||
),
|
||||
);
|
||||
$data = isset($this->data['data']) ? $this->data['data'] : [];
|
||||
$data['config'] = isset($this->data['config']) ? $this->data['config'] : $data;
|
||||
return View::config($config)->assign($data)->fetch($template);
|
||||
|
||||
return View::config($config)->assign($this->data)->fetch($template);
|
||||
}
|
||||
}
|
||||
@@ -116,7 +116,7 @@
|
||||
</ul>
|
||||
</li>
|
||||
<li class="visible-lg">
|
||||
<a href="#" class="btn" onclick="helpIntro();">
|
||||
<a href="#" class="btn hopscotch">
|
||||
<i class="fa fa-question-circle"></i>
|
||||
操作指南
|
||||
</a>
|
||||
@@ -168,19 +168,19 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
{block name="body"}
|
||||
<div class="main-box clearfix">
|
||||
<header class="main-box-header clearfix">
|
||||
<div class="pull-left">
|
||||
<h2>{$meta|default='新功能'}</h2>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
{block name="toolbar"}{/block}
|
||||
</div>
|
||||
</header>
|
||||
<div class="main-box-body clearfix">
|
||||
{block name="body"}{/block}
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -194,13 +194,11 @@
|
||||
</div>
|
||||
{include file="admin/setting"}
|
||||
<script src="__js__/skin-changer.js"></script>
|
||||
<script src="__static__/libs/jquery/jquery.min.js"></script>
|
||||
<script src="__static__/libs/bootstrap/js/bootstrap.min.js"></script>
|
||||
<script src="__static__/libs/nanoscroller/jquery.nanoscroller.min.js"></script>
|
||||
<script type="text/javascript" src="__static__/js/jquery.slimscroll.min.js"></script>
|
||||
<script src="__js__/app.js"></script>
|
||||
<script type="text/javascript" src="/static/js/vue.js"></script>
|
||||
<script type="text/javascript" src="/static/js/axios.min.js"></script>
|
||||
{block name="script"}{/block}
|
||||
<script type="text/javascript" src="__static__/libs/requirejs/require.js" data-main="__js__/main.js?v={$system_version|default='4.0.0'}"></script>
|
||||
{block name="script"}
|
||||
<script type="text/javascript">
|
||||
var isLoadModule = false;
|
||||
</script>
|
||||
{/block}
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,15 +1,23 @@
|
||||
{extend name="admin/base"/}
|
||||
{block name="toolbar"}
|
||||
<a href="{:url('Config/index')}" class="btn btn-primary">
|
||||
{block name="body"}
|
||||
|
||||
<div class="main-box clearfix">
|
||||
<header class="main-box-header clearfix">
|
||||
<div class="pull-left">
|
||||
<h2>{$meta|default='新功能'}</h2>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
<a href="{:url('Config/index')}" class="btn btn-primary">
|
||||
<i class="fa fa-list"></i>
|
||||
配置列表
|
||||
</a>
|
||||
<a href="{:url('Config/add')}" class="btn btn-danger">
|
||||
</a>
|
||||
<a href="{:url('Config/add')}" class="btn btn-danger">
|
||||
<i class="fa fa-list"></i>
|
||||
添加配置
|
||||
</a>
|
||||
{/block}
|
||||
{block name="body"}
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
<div class="main-box-body clearfix">
|
||||
<div class="tabs-wrapper">
|
||||
<ul class="nav nav-tabs">
|
||||
{volist name="config['config_group_list']" id="item"}
|
||||
@@ -72,19 +80,11 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
{block name="script"}
|
||||
<script type="text/javascript">
|
||||
var vm = new Vue({
|
||||
el:".vue-main",
|
||||
data:{},
|
||||
created(){
|
||||
$.ajax({
|
||||
success: function(res){
|
||||
console.log(res)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
var isLoadModule = true;
|
||||
</script>
|
||||
{/block}
|
||||
@@ -1,15 +1,10 @@
|
||||
{extend name="admin/base"/}
|
||||
|
||||
{block name="body"}
|
||||
<div class="main-box clearfix">
|
||||
<header class="main-box-header clearfix">
|
||||
<div class="pull-left">
|
||||
<h2>清除缓存</h2>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
</div>
|
||||
</header>
|
||||
<div class="main-box-body clearfix">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/block}
|
||||
{block name="script"}
|
||||
<script type="text/javascript">
|
||||
var isLoadModule = true;
|
||||
</script>
|
||||
{/block}
|
||||
@@ -64,7 +64,7 @@
|
||||
|
||||
</div>
|
||||
<script src="__static__/libs/jquery/jquery.min.js"></script>
|
||||
<script src="__static__/libs/layui/layui.all.js"></script>
|
||||
<script src="__static__/libs/layer/layer.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
//表单提交
|
||||
|
||||
290
public/static/admin/js/backend.js
Normal file
@@ -0,0 +1,290 @@
|
||||
define(['jquery', 'hopscotch'], function($, hopscotch){
|
||||
var Backend = {
|
||||
|
||||
writeStorage: function(storage, key, value) {
|
||||
if (storage) {
|
||||
try {
|
||||
localStorage.setItem(key, value);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
helpIntro: function(){
|
||||
var placementRight = 'right';
|
||||
var placementLeft = 'left';
|
||||
|
||||
if ($('body').hasClass('rtl')) {
|
||||
placementRight = 'left';
|
||||
placementLeft = 'right';
|
||||
}
|
||||
|
||||
// Define the tour!
|
||||
var tour = {
|
||||
id: "Cube-intro",
|
||||
steps: [
|
||||
{
|
||||
target: 'make-small-nav',
|
||||
title: "设置小菜单按钮",
|
||||
content: "点击小菜单可以把左侧菜单变成小菜单,增大右侧操作区域!",
|
||||
placement: "bottom",
|
||||
zindex: 999,
|
||||
xOffset: -8
|
||||
},
|
||||
{
|
||||
target: 'config-tool-options',
|
||||
title: "后台配置工具",
|
||||
content: "配置后台主题色彩,定制头部、左侧菜单以及底部信息",
|
||||
placement: placementLeft,
|
||||
zindex: 999,
|
||||
fixedElement: true,
|
||||
xOffset: -55
|
||||
},
|
||||
{
|
||||
target: 'sidebar-nav',
|
||||
title: "左侧导航区域",
|
||||
content: "左侧功能导航区域。",
|
||||
placement: placementRight
|
||||
}
|
||||
],
|
||||
showPrevButton: true
|
||||
};
|
||||
|
||||
console.log(hopscotch);
|
||||
// Start the tour!
|
||||
hopscotch.startTour(tour);
|
||||
},
|
||||
|
||||
init: function () {
|
||||
$('.hopscotch').on('click', function(){
|
||||
Backend.helpIntro()
|
||||
})
|
||||
|
||||
var storage, fail, uid;
|
||||
try {
|
||||
uid = new Date;
|
||||
(storage = window.localStorage).setItem(uid, uid);
|
||||
fail = storage.getItem(uid) != uid;
|
||||
storage.removeItem(uid);
|
||||
fail && (storage = false);
|
||||
} catch (e) {}
|
||||
if (storage) {
|
||||
try {
|
||||
var usedSkin = localStorage.getItem('config-skin');
|
||||
if (usedSkin != '') {
|
||||
$('#skin-colors .skin-changer').removeClass('active');
|
||||
$('#skin-colors .skin-changer[data-skin="' + usedSkin + '"]').addClass('active');
|
||||
}
|
||||
var fixedHeader = localStorage.getItem('config-fixed-header');
|
||||
if (fixedHeader == 'fixed-header') {
|
||||
$('body').addClass(fixedHeader);
|
||||
$('#config-fixed-header').prop('checked', true);
|
||||
}
|
||||
var fixedFooter = localStorage.getItem('config-fixed-footer');
|
||||
if (fixedFooter == 'fixed-footer') {
|
||||
$('body').addClass(fixedFooter);
|
||||
$('#config-fixed-footer').prop('checked', true);
|
||||
}
|
||||
var boxedLayout = localStorage.getItem('config-boxed-layout');
|
||||
if (boxedLayout == 'boxed-layout') {
|
||||
$('body').addClass(boxedLayout);
|
||||
$('#config-boxed-layout').prop('checked', true);
|
||||
}
|
||||
var rtlLayout = localStorage.getItem('config-rtl-layout');
|
||||
if (rtlLayout == 'rtl') {
|
||||
$('body').addClass(rtlLayout);
|
||||
$('#config-rtl-layout').prop('checked', true);
|
||||
}
|
||||
var fixedLeftmenu = localStorage.getItem('config-fixed-leftmenu');
|
||||
if (fixedLeftmenu == 'fixed-leftmenu') {
|
||||
$('body').addClass(fixedLeftmenu);
|
||||
$('#config-fixed-sidebar').prop('checked', true);
|
||||
if ($('#page-wrapper').hasClass('nav-small')) {
|
||||
$('#page-wrapper').removeClass('nav-small');
|
||||
}
|
||||
$('.fixed-leftmenu #col-left').nanoScroller({
|
||||
alwaysVisible: true,
|
||||
iOSNativeScrolling: false,
|
||||
preventPageScrolling: true,
|
||||
contentClass: 'col-left-nano-content'
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
$('#config-tool-cog').on('click', function() {
|
||||
$('#config-tool').toggleClass('closed');
|
||||
});
|
||||
$('#config-fixed-header').on('change', function() {
|
||||
var fixedHeader = '';
|
||||
if ($(this).is(':checked')) {
|
||||
$('body').addClass('fixed-header');
|
||||
fixedHeader = 'fixed-header';
|
||||
} else {
|
||||
$('body').removeClass('fixed-header');
|
||||
if ($('#config-fixed-sidebar').is(':checked')) {
|
||||
$('#config-fixed-sidebar').prop('checked', false);
|
||||
$('#config-fixed-sidebar').trigger('change');
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
Backend.writeStorage(storage, 'config-fixed-header', fixedHeader);
|
||||
});
|
||||
$('#config-fixed-footer').on('change', function() {
|
||||
var fixedFooter = '';
|
||||
if ($(this).is(':checked')) {
|
||||
$('body').addClass('fixed-footer');
|
||||
fixedFooter = 'fixed-footer';
|
||||
} else {
|
||||
$('body').removeClass('fixed-footer');
|
||||
}
|
||||
Backend.writeStorage(storage, 'config-fixed-footer', fixedFooter);
|
||||
});
|
||||
$('#config-boxed-layout').on('change', function() {
|
||||
var boxedLayout = '';
|
||||
if ($(this).is(':checked')) {
|
||||
$('body').addClass('boxed-layout');
|
||||
boxedLayout = 'boxed-layout';
|
||||
} else {
|
||||
$('body').removeClass('boxed-layout');
|
||||
}
|
||||
Backend.writeStorage(storage, 'config-boxed-layout', boxedLayout);
|
||||
});
|
||||
$('#config-rtl-layout').on('change', function() {
|
||||
var rtlLayout = '';
|
||||
if ($(this).is(':checked')) {
|
||||
rtlLayout = 'rtl';
|
||||
} else {}
|
||||
Backend.writeStorage(storage, 'config-rtl-layout', rtlLayout);
|
||||
location.reload();
|
||||
});
|
||||
$('#config-fixed-sidebar').on('change', function() {
|
||||
var fixedSidebar = '';
|
||||
if ($(this).is(':checked')) {
|
||||
if (!$('#config-fixed-header').is(':checked')) {
|
||||
$('#config-fixed-header').prop('checked', true);
|
||||
$('#config-fixed-header').trigger('change');
|
||||
}
|
||||
if ($('#page-wrapper').hasClass('nav-small')) {
|
||||
$('#page-wrapper').removeClass('nav-small');
|
||||
}
|
||||
$('body').addClass('fixed-leftmenu');
|
||||
fixedSidebar = 'fixed-leftmenu';
|
||||
$('.fixed-leftmenu #col-left').nanoScroller({
|
||||
alwaysVisible: true,
|
||||
iOSNativeScrolling: false,
|
||||
preventPageScrolling: true,
|
||||
contentClass: 'col-left-nano-content'
|
||||
});
|
||||
Backend.writeStorage(storage, 'config-fixed-leftmenu', fixedSidebar);
|
||||
} else {
|
||||
$('body').removeClass('fixed-leftmenu');
|
||||
Backend.writeStorage(storage, 'config-fixed-leftmenu', fixedSidebar);
|
||||
location.reload();
|
||||
}
|
||||
});
|
||||
if (!storage) {
|
||||
$('#config-fixed-header').prop('checked', false);
|
||||
$('#config-fixed-footer').prop('checked', false);
|
||||
$('#config-fixed-sidebar').prop('checked', false);
|
||||
$('#config-boxed-layout').prop('checked', false);
|
||||
$('#config-rtl-layout').prop('checked', false);
|
||||
}
|
||||
$('#skin-colors .skin-changer').on('click', function() {
|
||||
$('body').removeClassPrefix('theme-');
|
||||
$('body').addClass($(this).data('skin'));
|
||||
$('#skin-colors .skin-changer').removeClass('active');
|
||||
$(this).addClass('active');
|
||||
Backend.writeStorage(storage, 'config-skin', $(this).data('skin'));
|
||||
});
|
||||
setTimeout(function() {
|
||||
$('#content-wrapper > .row').css({
|
||||
opacity: 1
|
||||
});
|
||||
}, 200);
|
||||
$('#sidebar-nav,#nav-col-submenu').on('click', '.dropdown-toggle', function(e) {
|
||||
e.preventDefault();
|
||||
var $item = $(this).parent();
|
||||
if (!$item.hasClass('open')) {
|
||||
$item.parent().find('.open .submenu').slideUp('fast');
|
||||
$item.parent().find('.open').toggleClass('open');
|
||||
}
|
||||
$item.toggleClass('open');
|
||||
if ($item.hasClass('open')) {
|
||||
$item.children('.submenu').slideDown('fast');
|
||||
} else {
|
||||
$item.children('.submenu').slideUp('fast');
|
||||
}
|
||||
});
|
||||
$('body').on('mouseenter', '#page-wrapper.nav-small #sidebar-nav .dropdown-toggle', function(e) {
|
||||
if ($(document).width() >= 992) {
|
||||
var $item = $(this).parent();
|
||||
if ($('body').hasClass('fixed-leftmenu')) {
|
||||
var topPosition = $item.position().top;
|
||||
if ((topPosition + 4 * $(this).outerHeight()) >= $(window).height()) {
|
||||
topPosition -= 6 * $(this).outerHeight();
|
||||
}
|
||||
$('#nav-col-submenu').html($item.children('.submenu').clone());
|
||||
$('#nav-col-submenu > .submenu').css({
|
||||
'top': topPosition
|
||||
});
|
||||
}
|
||||
$item.addClass('open');
|
||||
$item.children('.submenu').slideDown('fast');
|
||||
}
|
||||
});
|
||||
$('body').on('mouseleave', '#page-wrapper.nav-small #sidebar-nav > .nav-pills > li', function(e) {
|
||||
if ($(document).width() >= 992) {
|
||||
var $item = $(this);
|
||||
if ($item.hasClass('open')) {
|
||||
$item.find('.open .submenu').slideUp('fast');
|
||||
$item.find('.open').removeClass('open');
|
||||
$item.children('.submenu').slideUp('fast');
|
||||
}
|
||||
$item.removeClass('open');
|
||||
}
|
||||
});
|
||||
$('body').on('mouseenter', '#page-wrapper.nav-small #sidebar-nav a:not(.dropdown-toggle)', function(e) {
|
||||
if ($('body').hasClass('fixed-leftmenu')) {
|
||||
$('#nav-col-submenu').html('');
|
||||
}
|
||||
});
|
||||
$('body').on('mouseleave', '#page-wrapper.nav-small #nav-col', function(e) {
|
||||
if ($('body').hasClass('fixed-leftmenu')) {
|
||||
$('#nav-col-submenu').html('');
|
||||
}
|
||||
});
|
||||
$('#make-small-nav').click(function(e) {
|
||||
$('#page-wrapper').toggleClass('nav-small');
|
||||
});
|
||||
|
||||
$('.mobile-search').click(function(e) {
|
||||
e.preventDefault();
|
||||
$('.mobile-search').addClass('active');
|
||||
$('.mobile-search form input.form-control').focus();
|
||||
});
|
||||
$(document).mouseup(function(e) {
|
||||
var container = $('.mobile-search');
|
||||
if (!container.is(e.target) && container.has(e.target).length === 0) {
|
||||
container.removeClass('active');
|
||||
}
|
||||
});
|
||||
$('.fixed-leftmenu #col-left').nanoScroller({
|
||||
alwaysVisible: false,
|
||||
iOSNativeScrolling: false,
|
||||
preventPageScrolling: true,
|
||||
contentClass: 'col-left-nano-content'
|
||||
});
|
||||
$("[data-toggle='tooltip']").each(function(index, el) {
|
||||
$(el).tooltip({
|
||||
placement: $(this).data("placement") || 'top'
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Backend.init(); //默认初始化执行的代码
|
||||
return Backend;
|
||||
})
|
||||
@@ -1,10 +1,174 @@
|
||||
require.config({
|
||||
paths:{
|
||||
'vue':'/static/js/vue.js',
|
||||
"jquery":'/static/libs/jquery/jquery.min.js'
|
||||
urlArgs: "v=" + '4.0.0',
|
||||
packages: [
|
||||
{
|
||||
name: 'moment',
|
||||
location: '/static/libs/moment',
|
||||
main: 'moment'
|
||||
}
|
||||
],
|
||||
include: ['jquery', 'drop', 'drag', 'form'],
|
||||
paths:{
|
||||
'backend': '../admin/js/backend',
|
||||
'form': '/static/js/require-form',
|
||||
'table': '/static/js/require-table',
|
||||
'upload': '/static/js/require-upload',
|
||||
'validator': '/static/js/require-validator',
|
||||
'drag': 'jquery.drag.min',
|
||||
'drop': 'jquery.drop.min',
|
||||
'echarts': 'echarts.min',
|
||||
'echarts-theme': 'echarts-theme',
|
||||
|
||||
"vue":'/static/libs/vue/dist/vue.min',
|
||||
"jquery":'/static/libs/jquery/jquery.min',
|
||||
"nanoscroller":"/static/libs/nanoscroller/jquery.nanoscroller.min",
|
||||
"slimscroll":"/static/js/jquery.slimscroll.min",
|
||||
"bootstrap":"/static/libs/bootstrap/js/bootstrap.min",
|
||||
'bootstrap-table-commonsearch': 'bootstrap-table-commonsearch',
|
||||
'bootstrap-table-template': 'bootstrap-table-template',
|
||||
//
|
||||
// 以下的包从bower的libs目录加载
|
||||
'jquery': '/static/libs/jquery/dist/jquery.min',
|
||||
'bootstrap': '/static/libs/bootstrap/dist/js/bootstrap.min',
|
||||
'bootstrap-datetimepicker': '/static/libs/eonasdan-bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min',
|
||||
'bootstrap-daterangepicker': '/static/libs/bootstrap-daterangepicker/daterangepicker',
|
||||
'bootstrap-select': '/static/libs/bootstrap-select/dist/js/bootstrap-select.min',
|
||||
'bootstrap-select-lang': '/static/libs/bootstrap-select/dist/js/i18n/defaults-zh_CN',
|
||||
'bootstrap-table': '/static/libs/bootstrap-table/dist/bootstrap-table.min',
|
||||
'bootstrap-table-export': '/static/libs/bootstrap-table/dist/extensions/export/bootstrap-table-export.min',
|
||||
'bootstrap-table-mobile': '/static/libs/bootstrap-table/dist/extensions/mobile/bootstrap-table-mobile',
|
||||
'bootstrap-table-lang': '/static/libs/bootstrap-table/dist/locale/bootstrap-table-zh-CN',
|
||||
'bootstrap-slider': '/static/libs/bootstrap-slider/bootstrap-slider',
|
||||
'tableexport': '/static/libs/tableExport.jquery.plugin/tableExport.min',
|
||||
'dragsort': '/static/libs/fastadmin-dragsort/jquery.dragsort',
|
||||
'sortable': '/static/libs/Sortable/Sortable.min',
|
||||
'addtabs': '/static/libs/fastadmin-addtabs/jquery.addtabs',
|
||||
'slimscroll': '/static/libs/jquery-slimscroll/jquery.slimscroll',
|
||||
'validator-core': '/static/libs/nice-validator/dist/jquery.validator',
|
||||
'validator-lang': '/static/libs/nice-validator/dist/local/zh-CN',
|
||||
'plupload': '/static/libs/plupload/js/plupload.min',
|
||||
'toastr': '/static/libs/toastr/toastr',
|
||||
'jstree': '/static/libs/jstree/dist/jstree.min',
|
||||
'layer': '/static/libs/fastadmin-layer/dist/layer',
|
||||
'cookie': '/static/libs/jquery.cookie/jquery.cookie',
|
||||
'cxselect': '/static/libs/fastadmin-cxselect/js/jquery.cxselect',
|
||||
'template': '/static/libs/art-template/dist/template-native',
|
||||
'selectpage': '/static/libs/fastadmin-selectpage/selectpage',
|
||||
'citypicker': '/static/libs/fastadmin-citypicker/dist/js/city-picker.min',
|
||||
'citypicker-data': '/static/libs/fastadmin-citypicker/dist/js/city-picker.data',
|
||||
},
|
||||
shim:{
|
||||
"nanoscroller":['jquery'],
|
||||
"slimscroll":{
|
||||
deps: ['jquery'],
|
||||
exports: '$.fn.extend'
|
||||
},
|
||||
'bootstrap': ['jquery'],
|
||||
'bootstrap-table': {
|
||||
deps: [
|
||||
'bootstrap',
|
||||
// 'css!/static/libs/bootstrap-table/dist/bootstrap-table.min.css'
|
||||
],
|
||||
exports: '$.fn.bootstrapTable'
|
||||
},
|
||||
'bootstrap-table-lang': {
|
||||
deps: ['bootstrap-table'],
|
||||
exports: '$.fn.bootstrapTable.defaults'
|
||||
},
|
||||
'bootstrap-table-export': {
|
||||
deps: ['bootstrap-table', 'tableexport'],
|
||||
exports: '$.fn.bootstrapTable.defaults'
|
||||
},
|
||||
'bootstrap-table-mobile': {
|
||||
deps: ['bootstrap-table'],
|
||||
exports: '$.fn.bootstrapTable.defaults'
|
||||
},
|
||||
'bootstrap-table-advancedsearch': {
|
||||
deps: ['bootstrap-table'],
|
||||
exports: '$.fn.bootstrapTable.defaults'
|
||||
},
|
||||
'bootstrap-table-commonsearch': {
|
||||
deps: ['bootstrap-table'],
|
||||
exports: '$.fn.bootstrapTable.defaults'
|
||||
},
|
||||
'bootstrap-table-template': {
|
||||
deps: ['bootstrap-table', 'template'],
|
||||
exports: '$.fn.bootstrapTable.defaults'
|
||||
},
|
||||
'tableexport': {
|
||||
deps: ['jquery'],
|
||||
exports: '$.fn.extend'
|
||||
},
|
||||
'bootstrap-datetimepicker': [
|
||||
'moment/locale/zh-cn.js',
|
||||
// 'css!/static/libs/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.min.css',
|
||||
],
|
||||
// 'bootstrap-select': ['css!/static/libs/bootstrap-select/dist/css/bootstrap-select.min.css',],
|
||||
'bootstrap-select-lang': ['bootstrap-select'],
|
||||
// 'toastr': ['css!/static/libs/toastr/toastr.min.css'],
|
||||
'jstree': ['css!/static/libs/jstree/dist/themes/default/style.css',],
|
||||
'plupload': {
|
||||
deps: ['/static/libs/plupload/js/moxie.min.js'],
|
||||
exports: "plupload"
|
||||
},
|
||||
// 'layer': ['css!/static/libs/fastadmin-layer/dist/theme/default/layer.css'],
|
||||
// 'validator-core': ['css!/static/libs/nice-validator/dist/jquery.validator.css'],
|
||||
'validator-lang': ['validator-core'],
|
||||
// 'selectpage': ['css!/static/libs/fastadmin-selectpage/selectpage.css'],
|
||||
'citypicker': ['citypicker-data', 'css!/static/libs/fastadmin-citypicker/dist/css/city-picker.css']
|
||||
},
|
||||
baseUrl:"/static/js/",
|
||||
map: {
|
||||
'*': {
|
||||
'css': '/static/libs/require-css/css.min.js'
|
||||
}
|
||||
},
|
||||
//baseUrl: '/static/admin/js/backend/',
|
||||
waitSeconds: 30,
|
||||
charset: 'utf-8' // 文件编码
|
||||
});
|
||||
|
||||
require(['vue', 'jquery'], function(Vue, $){
|
||||
require(['jquery', 'nanoscroller', 'bootstrap'], function($){
|
||||
$(function($) {
|
||||
require(['sent'], function(Sent){
|
||||
require(['backend', 'backend-init', 'addons'], function (Backend, undefined, Addons) {
|
||||
// 避免目录冲突
|
||||
require.config({baseUrl: '/static/admin/js/module/'});
|
||||
|
||||
var current_url = (window.location.pathname).split('/');
|
||||
if (typeof(isLoadModule) != "undefined" && isLoadModule) {
|
||||
require([current_url[2]], function(Controller){
|
||||
var action = current_url[3].split('.');
|
||||
if (Controller.hasOwnProperty(action[0])) {
|
||||
Controller[action[0]]();
|
||||
} else {
|
||||
if (Controller.hasOwnProperty("_empty")) {
|
||||
Controller._empty();
|
||||
}
|
||||
}
|
||||
}, function (e) {
|
||||
console.error(e); // 这里可捕获模块加载的错误
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
$.fn.removeClassPrefix = function(prefix) {
|
||||
this.each(function(i, el) {
|
||||
var classes = el.className.split(" ").filter(function(c) {
|
||||
return c.lastIndexOf(prefix, 0) !== 0;
|
||||
});
|
||||
el.className = classes.join(" ");
|
||||
});
|
||||
return this;
|
||||
};
|
||||
});
|
||||
|
||||
function setContentBody() {
|
||||
header_height = $('header#header-navbar').height();
|
||||
if ($(window).height() - header_height - 50 > $('#content-wrapper').height()) {
|
||||
$('#content-wrapper').height($(window).height() - header_height - 50);
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
8
public/static/admin/js/module/config.js
Normal file
@@ -0,0 +1,8 @@
|
||||
define([], function(){
|
||||
var controller = {
|
||||
group: function(){
|
||||
}
|
||||
}
|
||||
|
||||
return controller;
|
||||
})
|
||||
9
public/static/admin/js/module/index.js
Normal file
@@ -0,0 +1,9 @@
|
||||
define(['vue'],function(Vue){
|
||||
var controller = {
|
||||
clear: function(){
|
||||
var vm = new Vue();
|
||||
}
|
||||
}
|
||||
|
||||
return controller;
|
||||
})
|
||||
9
public/static/js/axios.min.js
vendored
179
public/static/js/hopscotch.js
Normal file
@@ -0,0 +1,179 @@
|
||||
(function(context,namespace){var Hopscotch,HopscotchBubble,HopscotchCalloutManager,HopscotchI18N,customI18N,customRenderer,customEscape,templateToUse='bubble_default',Sizzle=window.Sizzle||null,utils,callbacks,helpers,winLoadHandler,defaultOpts,winHopscotch=context[namespace],undefinedStr='undefined',waitingToStart=false,hasJquery=(typeof window.jQuery!==undefinedStr),hasSessionStorage=false,isStorageWritable=false,document=window.document;try{if(typeof window.sessionStorage!==undefinedStr){hasSessionStorage=true;sessionStorage.setItem('hopscotch.test.storage','ok');sessionStorage.removeItem('hopscotch.test.storage');isStorageWritable=true;}}catch(err){}
|
||||
defaultOpts={smoothScroll:true,scrollDuration:1000,scrollTopMargin:200,showCloseButton:true,showPrevButton:false,showNextButton:true,bubbleWidth:280,bubblePadding:15,arrowWidth:20,skipIfNoElement:true,cookieName:'hopscotch.tour.state'};if(winHopscotch){return;}
|
||||
if(!Array.isArray){Array.isArray=function(obj){return Object.prototype.toString.call(obj)==='[object Array]';};}
|
||||
winLoadHandler=function(){if(waitingToStart){winHopscotch.startTour();}};utils={addClass:function(domEl,classToAdd){var domClasses,classToAddArr,setClass,i,len;if(!domEl.className){domEl.className=classToAdd;}
|
||||
else{classToAddArr=classToAdd.split(/\s+/);domClasses=' '+ domEl.className+' ';for(i=0,len=classToAddArr.length;i<len;++i){if(domClasses.indexOf(' '+ classToAddArr[i]+' ')<0){domClasses+=classToAddArr[i]+' ';}}
|
||||
domEl.className=domClasses.replace(/^\s+|\s+$/g,'');}},removeClass:function(domEl,classToRemove){var domClasses,classToRemoveArr,currClass,i,len;classToRemoveArr=classToRemove.split(/\s+/);domClasses=' '+ domEl.className+' ';for(i=0,len=classToRemoveArr.length;i<len;++i){domClasses=domClasses.replace(' '+ classToRemoveArr[i]+' ',' ');}
|
||||
domEl.className=domClasses.replace(/^\s+|\s+$/g,'');},hasClass:function(domEl,classToCheck){var classes;if(!domEl.className){return false;}
|
||||
classes=' '+ domEl.className+' ';return(classes.indexOf(' '+ classToCheck+' ')!==-1);},getPixelValue:function(val){var valType=typeof val;if(valType==='number'){return val;}
|
||||
if(valType==='string'){return parseInt(val,10);}
|
||||
return 0;},valOrDefault:function(val,valDefault){return typeof val!==undefinedStr?val:valDefault;},invokeCallbackArrayHelper:function(arr){var fn;if(Array.isArray(arr)){fn=helpers[arr[0]];if(typeof fn==='function'){return fn.apply(this,arr.slice(1));}}},invokeCallbackArray:function(arr){var i,len;if(Array.isArray(arr)){if(typeof arr[0]==='string'){return utils.invokeCallbackArrayHelper(arr);}
|
||||
else{for(i=0,len=arr.length;i<len;++i){utils.invokeCallback(arr[i]);}}}},invokeCallback:function(cb){if(typeof cb==='function'){return cb();}
|
||||
if(typeof cb==='string'&&helpers[cb]){return helpers[cb]();}
|
||||
else{return utils.invokeCallbackArray(cb);}},invokeEventCallbacks:function(evtType,stepCb){var cbArr=callbacks[evtType],callback,fn,i,len;if(stepCb){return this.invokeCallback(stepCb);}
|
||||
for(i=0,len=cbArr.length;i<len;++i){this.invokeCallback(cbArr[i].cb);}},getScrollTop:function(){var scrollTop;if(typeof window.pageYOffset!==undefinedStr){scrollTop=window.pageYOffset;}
|
||||
else{scrollTop=document.documentElement.scrollTop;}
|
||||
return scrollTop;},getScrollLeft:function(){var scrollLeft;if(typeof window.pageXOffset!==undefinedStr){scrollLeft=window.pageXOffset;}
|
||||
else{scrollLeft=document.documentElement.scrollLeft;}
|
||||
return scrollLeft;},getWindowHeight:function(){return window.innerHeight||document.documentElement.clientHeight;},getWindowWidth:function(){return window.innerWidth||document.documentElement.clientWidth;},addEvtListener:function(el,evtName,fn){return el.addEventListener?el.addEventListener(evtName,fn,false):el.attachEvent('on'+ evtName,fn);},removeEvtListener:function(el,evtName,fn){return el.removeEventListener?el.removeEventListener(evtName,fn,false):el.detachEvent('on'+ evtName,fn);},documentIsReady:function(){return document.readyState==='complete'||document.readyState==='interactive';},evtPreventDefault:function(evt){if(evt.preventDefault){evt.preventDefault();}
|
||||
else if(event){event.returnValue=false;}},extend:function(obj1,obj2){var prop;for(prop in obj2){if(obj2.hasOwnProperty(prop)){obj1[prop]=obj2[prop];}}},getStepTargetHelper:function(target){var result=document.getElementById(target);if(result){return result;}
|
||||
if(hasJquery){result=jQuery(target);return result.length?result[0]:null;}
|
||||
if(Sizzle){result=new Sizzle(target);return result.length?result[0]:null;}
|
||||
if(document.querySelector){try{return document.querySelector(target);}catch(err){}}
|
||||
if(/^#[a-zA-Z][\w-_:.]*$/.test(target)){return document.getElementById(target.substring(1));}
|
||||
return null;},getStepTarget:function(step){var queriedTarget;if(!step||!step.target){return null;}
|
||||
if(typeof step.target==='string'){return utils.getStepTargetHelper(step.target);}
|
||||
else if(Array.isArray(step.target)){var i,len;for(i=0,len=step.target.length;i<len;i++){if(typeof step.target[i]==='string'){queriedTarget=utils.getStepTargetHelper(step.target[i]);if(queriedTarget){return queriedTarget;}}}
|
||||
return null;}
|
||||
return step.target;},getI18NString:function(key){return customI18N[key]||HopscotchI18N[key];},setState:function(name,value,days){var expires='',date;if(hasSessionStorage&&isStorageWritable){try{sessionStorage.setItem(name,value);}
|
||||
catch(err){isStorageWritable=false;this.setState(name,value,days);}}
|
||||
else{if(hasSessionStorage){sessionStorage.removeItem(name);}
|
||||
if(days){date=new Date();date.setTime(date.getTime()+(days*24*60*60*1000));expires='; expires='+date.toGMTString();}
|
||||
document.cookie=name+'='+value+expires+'; path=/';}},getState:function(name){var nameEQ=name+'=',ca=document.cookie.split(';'),i,c,state;if(hasSessionStorage){state=sessionStorage.getItem(name);if(state){return state;}}
|
||||
for(i=0;i<ca.length;i++){c=ca[i];while(c.charAt(0)===' '){c=c.substring(1,c.length);}
|
||||
if(c.indexOf(nameEQ)===0){state=c.substring(nameEQ.length,c.length);break;}}
|
||||
return state;},clearState:function(name){if(hasSessionStorage){sessionStorage.removeItem(name);}
|
||||
else{this.setState(name,'',-1);}}};utils.addEvtListener(window,'load',winLoadHandler);callbacks={next:[],prev:[],start:[],end:[],show:[],error:[],close:[]};helpers={};HopscotchI18N={stepNums:null,nextBtn:'Next',prevBtn:'Back',doneBtn:'Done',skipBtn:'Skip',closeTooltip:'Close'};customI18N={};HopscotchBubble=function(opt){this.init(opt);};HopscotchBubble.prototype={isShowing:false,currStep:undefined,setPosition:function(step){var bubbleBoundingHeight,bubbleBoundingWidth,boundingRect,top,left,arrowOffset,targetEl=utils.getStepTarget(step),el=this.element,arrowEl=this.arrowEl;bubbleBoundingWidth=el.offsetWidth;bubbleBoundingHeight=el.offsetHeight;utils.removeClass(el,'fade-in-down fade-in-up fade-in-left fade-in-right');if(!step.placement&&step.orientation){step.placement=step.orientation;}
|
||||
boundingRect=targetEl.getBoundingClientRect();if(step.placement==='top'){top=(boundingRect.top- bubbleBoundingHeight)- this.opt.arrowWidth;left=boundingRect.left;}
|
||||
else if(step.placement==='bottom'){top=boundingRect.bottom+ this.opt.arrowWidth;left=boundingRect.left;}
|
||||
else if(step.placement==='left'){top=boundingRect.top;left=boundingRect.left- bubbleBoundingWidth- this.opt.arrowWidth;}
|
||||
else if(step.placement==='right'){top=boundingRect.top;left=boundingRect.right+ this.opt.arrowWidth;}
|
||||
else{throw'Bubble placement failed because step.placement is invalid or undefined!';}
|
||||
if(step.arrowOffset!=='center'){arrowOffset=utils.getPixelValue(step.arrowOffset);}
|
||||
else{arrowOffset=step.arrowOffset;}
|
||||
if(!arrowOffset){arrowEl.style.top='';arrowEl.style.left='';}
|
||||
else if(step.placement==='top'||step.placement==='bottom'){arrowEl.style.top='';if(arrowOffset==='center'){arrowEl.style.left=Math.floor((bubbleBoundingWidth/2)- arrowEl.offsetWidth/2)+'px';}
|
||||
else{arrowEl.style.left=arrowOffset+'px';}}
|
||||
else if(step.placement==='left'||step.placement==='right'){arrowEl.style.left='';if(arrowOffset==='center'){arrowEl.style.top=Math.floor((bubbleBoundingHeight/2)- arrowEl.offsetHeight/2)+'px';}
|
||||
else{arrowEl.style.top=arrowOffset+'px';}}
|
||||
if(step.xOffset==='center'){left=(boundingRect.left+ targetEl.offsetWidth/2)-(bubbleBoundingWidth/2);}
|
||||
else{left+=utils.getPixelValue(step.xOffset);}
|
||||
if(step.yOffset==='center'){top=(boundingRect.top+ targetEl.offsetHeight/2)-(bubbleBoundingHeight/2);}
|
||||
else{top+=utils.getPixelValue(step.yOffset);}
|
||||
if(!step.fixedElement){top+=utils.getScrollTop();left+=utils.getScrollLeft();}
|
||||
el.style.position=(step.fixedElement?'fixed':'absolute');el.style.top=top+'px';el.style.left=left+'px';},render:function(step,idx,callback){var el=this.element,tourSpecificRenderer,customTourData,unsafe,currTour,totalSteps,nextBtnText,isLast,opts;if(step){this.currStep=step;}
|
||||
else if(this.currStep){step=this.currStep;}
|
||||
if(this.opt.isTourBubble){currTour=winHopscotch.getCurrTour();if(currTour){customTourData=currTour.customData;tourSpecificRenderer=currTour.customRenderer;unsafe=currTour.unsafe;if(Array.isArray(currTour.steps)){totalSteps=currTour.steps.length;isLast=(idx===totalSteps- 1);}}}else{customTourData=step.customData;tourSpecificRenderer=step.customRenderer;unsafe=step.unsafe;}
|
||||
if(isLast){nextBtnText=utils.getI18NString('doneBtn');}else if(step.showSkip){nextBtnText=utils.getI18NString('skipBtn');}else{nextBtnText=utils.getI18NString('nextBtn');}
|
||||
if(!step.placement&&step.orientation){step.placement=step.orientation;}
|
||||
this.placement=step.placement;opts={i18n:{prevBtn:utils.getI18NString('prevBtn'),nextBtn:nextBtnText,closeTooltip:utils.getI18NString('closeTooltip'),stepNum:this._getStepI18nNum(idx),},buttons:{showPrev:(utils.valOrDefault(step.showPrevButton,this.opt.showPrevButton)&&(idx>0)),showNext:utils.valOrDefault(step.showNextButton,this.opt.showNextButton),showCTA:utils.valOrDefault((step.showCTAButton&&step.ctaLabel),false),ctaLabel:step.ctaLabel,showClose:utils.valOrDefault(this.opt.showCloseButton,true)},step:{num:idx,isLast:utils.valOrDefault(isLast,false),title:(step.title||''),content:(step.content||''),placement:step.placement,padding:utils.valOrDefault(step.padding,this.opt.bubblePadding),width:utils.getPixelValue(step.width)||this.opt.bubbleWidth,customData:(step.customData||{})},tour:{isTour:this.opt.isTourBubble,numSteps:totalSteps,unsafe:utils.valOrDefault(unsafe,false),customData:(customTourData||{})}};if(typeof tourSpecificRenderer==='function'){el.innerHTML=tourSpecificRenderer(opts);}
|
||||
else if(typeof tourSpecificRenderer==='string'){if(!hopscotch.templates||(typeof hopscotch.templates[tourSpecificRenderer]!=='function')){throw'Bubble rendering failed - template "'+ tourSpecificRenderer+'" is not a function.';}
|
||||
el.innerHTML=hopscotch.templates[tourSpecificRenderer](opts);}
|
||||
else if(customRenderer){el.innerHTML=customRenderer(opts);}
|
||||
else{if(!hopscotch.templates||(typeof hopscotch.templates[templateToUse]!=='function')){throw'Bubble rendering failed - template "'+ templateToUse+'" is not a function.';}
|
||||
el.innerHTML=hopscotch.templates[templateToUse](opts);}
|
||||
children=el.children;numChildren=children.length;for(i=0;i<numChildren;i++){node=children[i];if(utils.hasClass(node,'hopscotch-arrow')){this.arrowEl=node;}}
|
||||
el.style.zIndex=(typeof step.zindex==='number')?step.zindex:'auto';this._setArrow(step.placement);this.hide(false);this.setPosition(step);if(callback){callback(!step.fixedElement);}
|
||||
return this;},_getStepI18nNum:function(idx){var stepNumI18N=utils.getI18NString('stepNums');if(stepNumI18N&&idx<stepNumI18N.length){idx=stepNumI18N[idx];}
|
||||
else{idx=idx+ 1;}
|
||||
return idx;},_setArrow:function(orientation){utils.removeClass(this.arrowEl,'down up right left');if(orientation==='top'){utils.addClass(this.arrowEl,'down');}
|
||||
else if(orientation==='bottom'){utils.addClass(this.arrowEl,'up');}
|
||||
else if(orientation==='left'){utils.addClass(this.arrowEl,'right');}
|
||||
else if(orientation==='right'){utils.addClass(this.arrowEl,'left');}},_getArrowDirection:function(){if(this.placement==='top'){return'down';}
|
||||
if(this.placement==='bottom'){return'up';}
|
||||
if(this.placement==='left'){return'right';}
|
||||
if(this.placement==='right'){return'left';}},show:function(){var self=this,fadeClass='fade-in-'+ this._getArrowDirection(),fadeDur=1000;utils.removeClass(this.element,'hide');utils.addClass(this.element,fadeClass);setTimeout(function(){utils.removeClass(self.element,'invisible');},50);setTimeout(function(){utils.removeClass(self.element,fadeClass);},fadeDur);this.isShowing=true;return this;},hide:function(remove){var el=this.element;remove=utils.valOrDefault(remove,true);el.style.top='';el.style.left='';if(remove){utils.addClass(el,'hide');utils.removeClass(el,'invisible');}
|
||||
else{utils.removeClass(el,'hide');utils.addClass(el,'invisible');}
|
||||
utils.removeClass(el,'animate fade-in-up fade-in-down fade-in-right fade-in-left');this.isShowing=false;return this;},destroy:function(){var el=this.element;if(el){el.parentNode.removeChild(el);}
|
||||
utils.removeEvtListener(el,'click',this.clickCb);},_handleBubbleClick:function(evt){var action;evt=evt||window.event;var targetElement=evt.target||evt.srcElement;function findMatchRecur(el){if(el===evt.currentTarget){return null;}
|
||||
if(utils.hasClass(el,'hopscotch-cta')){return'cta';}
|
||||
if(utils.hasClass(el,'hopscotch-next')){return'next';}
|
||||
if(utils.hasClass(el,'hopscotch-prev')){return'prev';}
|
||||
if(utils.hasClass(el,'hopscotch-close')){return'close';}
|
||||
return findMatchRecur(el.parentElement);}
|
||||
action=findMatchRecur(targetElement);if(action==='cta'){if(!this.opt.isTourBubble){winHopscotch.getCalloutManager().removeCallout(this.currStep.id);}
|
||||
if(this.currStep.onCTA){utils.invokeCallback(this.currStep.onCTA);}}
|
||||
else if(action==='next'){winHopscotch.nextStep(true);}
|
||||
else if(action==='prev'){winHopscotch.prevStep(true);}
|
||||
else if(action==='close'){if(this.opt.isTourBubble){var currStepNum=winHopscotch.getCurrStepNum(),currTour=winHopscotch.getCurrTour(),doEndCallback=(currStepNum===currTour.steps.length-1);utils.invokeEventCallbacks('close');winHopscotch.endTour(true,doEndCallback);}else{if(this.opt.onClose){utils.invokeCallback(this.opt.onClose);}
|
||||
if(this.opt.id&&!this.opt.isTourBubble){winHopscotch.getCalloutManager().removeCallout(this.opt.id);}
|
||||
else{this.destroy();}}
|
||||
utils.evtPreventDefault(evt);}},init:function(initOpt){var el=document.createElement('div'),self=this,resizeCooldown=false,onWinResize,appendToBody,children,numChildren,node,i,opt;this.element=el;opt={showPrevButton:defaultOpts.showPrevButton,showNextButton:defaultOpts.showNextButton,bubbleWidth:defaultOpts.bubbleWidth,bubblePadding:defaultOpts.bubblePadding,arrowWidth:defaultOpts.arrowWidth,showNumber:true,isTourBubble:true};initOpt=(typeof initOpt===undefinedStr?{}:initOpt);utils.extend(opt,initOpt);this.opt=opt;el.className='hopscotch-bubble animated';if(!opt.isTourBubble){utils.addClass(el,'hopscotch-callout no-number');}
|
||||
onWinResize=function(){if(resizeCooldown||!self.isShowing){return;}
|
||||
resizeCooldown=true;setTimeout(function(){self.setPosition(self.currStep);resizeCooldown=false;},100);};utils.addEvtListener(window,'resize',onWinResize);this.clickCb=function(evt){self._handleBubbleClick(evt);};utils.addEvtListener(el,'click',this.clickCb);this.hide();if(utils.documentIsReady()){document.body.appendChild(el);}
|
||||
else{if(document.addEventListener){appendToBody=function(){document.removeEventListener('DOMContentLoaded',appendToBody);window.removeEventListener('load',appendToBody);document.body.appendChild(el);};document.addEventListener('DOMContentLoaded',appendToBody,false);}
|
||||
else{appendToBody=function(){if(document.readyState==='complete'){document.detachEvent('onreadystatechange',appendToBody);window.detachEvent('onload',appendToBody);document.body.appendChild(el);}};document.attachEvent('onreadystatechange',appendToBody);}
|
||||
utils.addEvtListener(window,'load',appendToBody);}}};HopscotchCalloutManager=function(){var callouts={};this.createCallout=function(opt){var callout;if(opt.id){if(callouts[opt.id]){throw'Callout by that id already exists. Please choose a unique id.';}
|
||||
opt.showNextButton=opt.showPrevButton=false;opt.isTourBubble=false;callout=new HopscotchBubble(opt);callouts[opt.id]=callout;if(opt.target){callout.render(opt,null,function(){callout.show();});}}
|
||||
else{throw'Must specify a callout id.';}
|
||||
return callout;};this.getCallout=function(id){return callouts[id];};this.removeAllCallouts=function(){var calloutId,callout;for(calloutId in callouts){if(callouts.hasOwnProperty(calloutId)){this.removeCallout(calloutId);}}};this.removeCallout=function(id){var callout=callouts[id];callouts[id]=null;if(!callout){return;}
|
||||
callout.destroy();};};Hopscotch=function(initOptions){var self=this,bubble,calloutMgr,opt,currTour,currStepNum,cookieTourId,cookieTourStep,_configure,getBubble=function(setOptions){if(!bubble){bubble=new HopscotchBubble(opt);}
|
||||
if(setOptions){utils.extend(bubble.opt,{bubblePadding:getOption('bubblePadding'),bubbleWidth:getOption('bubbleWidth'),showNextButton:getOption('showNextButton'),showPrevButton:getOption('showPrevButton'),showCloseButton:getOption('showCloseButton'),arrowWidth:getOption('arrowWidth')});}
|
||||
return bubble;},getOption=function(name){if(typeof opt==='undefined'){return defaultOpts[name];}
|
||||
return utils.valOrDefault(opt[name],defaultOpts[name]);},getCurrStep=function(){var step;if(currStepNum<0||currStepNum>=currTour.steps.length){step=null;}
|
||||
else{step=currTour.steps[currStepNum];}
|
||||
return step;},targetClickNextFn=function(){self.nextStep();},adjustWindowScroll=function(cb){var bubble=getBubble(),bubbleEl=bubble.element,bubbleTop=utils.getPixelValue(bubbleEl.style.top),bubbleBottom=bubbleTop+ utils.getPixelValue(bubbleEl.offsetHeight),targetEl=utils.getStepTarget(getCurrStep()),targetBounds=targetEl.getBoundingClientRect(),targetElTop=targetBounds.top+ utils.getScrollTop(),targetElBottom=targetBounds.bottom+ utils.getScrollTop(),targetTop=(bubbleTop<targetElTop)?bubbleTop:targetElTop,targetBottom=(bubbleBottom>targetElBottom)?bubbleBottom:targetElBottom,windowTop=utils.getScrollTop(),windowBottom=windowTop+ utils.getWindowHeight(),scrollToVal=targetTop- getOption('scrollTopMargin'),scrollEl,yuiAnim,yuiEase,direction,scrollIncr,scrollTimeout,scrollTimeoutFn;if(targetTop>=windowTop&&(targetTop<=windowTop+ getOption('scrollTopMargin')||targetBottom<=windowBottom)){if(cb){cb();}}
|
||||
else if(!getOption('smoothScroll')){window.scrollTo(0,scrollToVal);if(cb){cb();}}
|
||||
else{if(typeof YAHOO!==undefinedStr&&typeof YAHOO.env!==undefinedStr&&typeof YAHOO.env.ua!==undefinedStr&&typeof YAHOO.util!==undefinedStr&&typeof YAHOO.util.Scroll!==undefinedStr){scrollEl=YAHOO.env.ua.webkit?document.body:document.documentElement;yuiEase=YAHOO.util.Easing?YAHOO.util.Easing.easeOut:undefined;yuiAnim=new YAHOO.util.Scroll(scrollEl,{scroll:{to:[0,scrollToVal]}},getOption('scrollDuration')/1000, yuiEase);
|
||||
yuiAnim.onComplete.subscribe(cb);yuiAnim.animate();}
|
||||
else if(hasJquery){jQuery('body, html').animate({scrollTop:scrollToVal},getOption('scrollDuration'),cb);}
|
||||
else{if(scrollToVal<0){scrollToVal=0;}
|
||||
direction=(windowTop>targetTop)?-1:1;scrollIncr=Math.abs(windowTop- scrollToVal)/ (getOption('scrollDuration')/10);
|
||||
scrollTimeoutFn=function(){var scrollTop=utils.getScrollTop(),scrollTarget=scrollTop+(direction*scrollIncr);if((direction>0&&scrollTarget>=scrollToVal)||(direction<0&&scrollTarget<=scrollToVal)){scrollTarget=scrollToVal;if(cb){cb();}
|
||||
window.scrollTo(0,scrollTarget);return;}
|
||||
window.scrollTo(0,scrollTarget);if(utils.getScrollTop()===scrollTop){if(cb){cb();}
|
||||
return;}
|
||||
setTimeout(scrollTimeoutFn,10);};scrollTimeoutFn();}}},goToStepWithTarget=function(direction,cb){var target,step,goToStepFn;if(currStepNum+ direction>=0&&currStepNum+ direction<currTour.steps.length){currStepNum+=direction;step=getCurrStep();goToStepFn=function(){target=utils.getStepTarget(step);if(target){cb(currStepNum);}
|
||||
else{utils.invokeEventCallbacks('error');goToStepWithTarget(direction,cb);}};if(step.delay){setTimeout(goToStepFn,step.delay);}
|
||||
else{goToStepFn();}}
|
||||
else{cb(-1);}},changeStep=function(doCallbacks,direction){var bubble=getBubble(),self=this,step,origStep,wasMultiPage,changeStepCb;bubble.hide();doCallbacks=utils.valOrDefault(doCallbacks,true);step=getCurrStep();origStep=step;if(direction>0){wasMultiPage=origStep.multipage;}
|
||||
else{wasMultiPage=(currStepNum>0&&currTour.steps[currStepNum-1].multipage);}
|
||||
changeStepCb=function(stepNum){var doShowFollowingStep;if(stepNum===-1){return this.endTour(true);}
|
||||
if(doCallbacks){if(direction>0){doShowFollowingStep=utils.invokeEventCallbacks('next',origStep.onNext);}
|
||||
else{doShowFollowingStep=utils.invokeEventCallbacks('prev',origStep.onPrev);}}
|
||||
if(stepNum!==currStepNum){return;}
|
||||
if(wasMultiPage){utils.setState(getOption('cookieName'),currTour.id+':'+ currStepNum,1);return;}
|
||||
doShowFollowingStep=utils.valOrDefault(doShowFollowingStep,true);if(doShowFollowingStep){this.showStep(stepNum);}
|
||||
else{this.endTour(false);}};if(!wasMultiPage&&getOption('skipIfNoElement')){goToStepWithTarget(direction,function(stepNum){changeStepCb.call(self,stepNum);});}
|
||||
else if(currStepNum+ direction>=0&&currStepNum+ direction<currTour.steps.length){currStepNum+=direction;step=getCurrStep();if(!utils.getStepTarget(step)&&!wasMultiPage){utils.invokeEventCallbacks('error');return this.endTour(true,false);}
|
||||
changeStepCb.call(this,currStepNum);}
|
||||
return this;},loadTour=function(tour){var tmpOpt={},prop,tourState,tourPair;for(prop in tour){if(tour.hasOwnProperty(prop)&&prop!=='id'&&prop!=='steps'){tmpOpt[prop]=tour[prop];}}
|
||||
_configure.call(this,tmpOpt,true);tourState=utils.getState(getOption('cookieName'));if(tourState){tourPair=tourState.split(':');cookieTourId=tourPair[0];cookieTourStep=tourPair[1];cookieTourStep=parseInt(cookieTourStep,10);}
|
||||
return this;},findStartingStep=function(startStepNum,cb){var step,target,stepNum;currStepNum=startStepNum||0;step=getCurrStep();target=utils.getStepTarget(step);if(target){cb(currStepNum);return;}
|
||||
if(!target){utils.invokeEventCallbacks('error');if(getOption('skipIfNoElement')){goToStepWithTarget(1,cb);return;}
|
||||
else{currStepNum=-1;cb(currStepNum);}}},showStepHelper=function(stepNum){var step=currTour.steps[stepNum],tourSteps=currTour.steps,numTourSteps=tourSteps.length,cookieVal=currTour.id+':'+ stepNum,bubble=getBubble(),targetEl=utils.getStepTarget(step),isLast,showBubble;showBubble=function(){bubble.show();utils.invokeEventCallbacks('show',step.onShow);};currStepNum=stepNum;bubble.hide(false);isLast=(stepNum===numTourSteps- 1);bubble.render(step,stepNum,function(adjustScroll){if(adjustScroll){adjustWindowScroll(showBubble);}
|
||||
else{showBubble();}
|
||||
if(step.nextOnTargetClick){utils.addEvtListener(targetEl,'click',targetClickNextFn);}});utils.setState(getOption('cookieName'),cookieVal,1);},init=function(initOptions){if(initOptions){this.configure(initOptions);}};this.getCalloutManager=function(){if(typeof calloutMgr===undefinedStr){calloutMgr=new HopscotchCalloutManager();}
|
||||
return calloutMgr;};this.startTour=function(tour,stepNum){var bubble,currStepNum,self=this;if(!currTour){currTour=tour;loadTour.call(this,tour);}
|
||||
if(typeof stepNum!==undefinedStr){if(stepNum>=currTour.steps.length){throw'Specified step number out of bounds.';}
|
||||
currStepNum=stepNum;}
|
||||
if(!utils.documentIsReady()){waitingToStart=true;return this;}
|
||||
if(typeof currStepNum==="undefined"&&currTour.id===cookieTourId&&typeof cookieTourStep!==undefinedStr){currStepNum=cookieTourStep;}
|
||||
else if(!currStepNum){currStepNum=0;}
|
||||
findStartingStep(currStepNum,function(stepNum){var target=(stepNum!==-1)&&utils.getStepTarget(currTour.steps[stepNum]);if(!target){self.endTour(false,false);return;}
|
||||
utils.invokeEventCallbacks('start');bubble=getBubble();bubble.hide(false);self.isActive=true;if(!utils.getStepTarget(getCurrStep())){utils.invokeEventCallbacks('error');if(getOption('skipIfNoElement')){self.nextStep(false);}}
|
||||
else{self.showStep(stepNum);}});return this;};this.showStep=function(stepNum){var step=currTour.steps[stepNum];if(step.delay){setTimeout(function(){showStepHelper(stepNum);},step.delay);}
|
||||
else{showStepHelper(stepNum);}
|
||||
return this;};this.prevStep=function(doCallbacks){changeStep.call(this,doCallbacks,-1);return this;};this.nextStep=function(doCallbacks){var step=getCurrStep(),targetEl=utils.getStepTarget(step);if(step.nextOnTargetClick){utils.removeEvtListener(targetEl,'click',targetClickNextFn);}
|
||||
changeStep.call(this,doCallbacks,1);return this;};this.endTour=function(clearState,doCallbacks){var bubble=getBubble();clearState=utils.valOrDefault(clearState,true);doCallbacks=utils.valOrDefault(doCallbacks,true);currStepNum=0;cookieTourStep=undefined;bubble.hide();if(clearState){utils.clearState(getOption('cookieName'));}
|
||||
if(this.isActive){this.isActive=false;if(currTour&&doCallbacks){utils.invokeEventCallbacks('end');}}
|
||||
this.removeCallbacks(null,true);this.resetDefaultOptions();currTour=null;return this;};this.getCurrTour=function(){return currTour;};this.getCurrTarget=function(){return utils.getStepTarget(getCurrStep());};this.getCurrStepNum=function(){return currStepNum;};this.refreshBubblePosition=function(){bubble.setPosition(getCurrStep());return this;};this.listen=function(evtType,cb,isTourCb){if(evtType){callbacks[evtType].push({cb:cb,fromTour:isTourCb});}
|
||||
return this;};this.unlisten=function(evtType,cb){var evtCallbacks=callbacks[evtType],i,len;for(i=0,len=evtCallbacks.length;i<len;++i){if(evtCallbacks[i]===cb){evtCallbacks.splice(i,1);}}
|
||||
return this;};this.removeCallbacks=function(evtName,tourOnly){var cbArr,i,len,evt;for(evt in callbacks){if(!evtName||evtName===evt){if(tourOnly){cbArr=callbacks[evt];for(i=0,len=cbArr.length;i<len;++i){if(cbArr[i].fromTour){cbArr.splice(i--,1);--len;}}}
|
||||
else{callbacks[evt]=[];}}}
|
||||
return this;};this.registerHelper=function(id,fn){if(typeof id==='string'&&typeof fn==='function'){helpers[id]=fn;}};this.unregisterHelper=function(id){helpers[id]=null;};this.invokeHelper=function(id){var args=[],i,len;for(i=1,len=arguments.length;i<len;++i){args.push(arguments[i]);}
|
||||
if(helpers[id]){helpers[id].call(null,args);}};this.setCookieName=function(name){opt.cookieName=name;return this;};this.resetDefaultOptions=function(){opt={};return this;};this.resetDefaultI18N=function(){customI18N={};return this;};this.getState=function(){return utils.getState(getOption('cookieName'));};_configure=function(options,isTourOptions){var bubble,events=['next','prev','start','end','show','error','close'],eventPropName,callbackProp,i,len;if(!opt){this.resetDefaultOptions();}
|
||||
utils.extend(opt,options);if(options){utils.extend(customI18N,options.i18n);}
|
||||
for(i=0,len=events.length;i<len;++i){eventPropName='on'+ events[i].charAt(0).toUpperCase()+ events[i].substring(1);if(options[eventPropName]){this.listen(events[i],options[eventPropName],isTourOptions);}}
|
||||
bubble=getBubble(true);return this;};this.configure=function(options){return _configure.call(this,options,false);};this.setRenderer=function(render){var typeOfRender=typeof render;if(typeOfRender==='string'){templateToUse=render;customRenderer=undefined;}
|
||||
else if(typeOfRender==='function'){customRenderer=render;}
|
||||
return this;};this.setEscaper=function(esc){if(typeof esc==='function'){customEscape=esc;}
|
||||
return this;};init.call(this,initOptions);};winHopscotch=new Hopscotch();context[namespace]=winHopscotch;(function(){var _={};_.escape=function(str){if(customEscape){return customEscape(str);}
|
||||
if(str==null)return'';return(''+ str).replace(new RegExp('[&<>"\']','g'),function(match){if(match=='&'){return'&'}
|
||||
if(match=='<'){return'<'}
|
||||
if(match=='>'){return'>'}
|
||||
if(match=='"'){return'"'}
|
||||
if(match=="'"){return'''}});}
|
||||
this["hopscotch"]=this["hopscotch"]||{};this["hopscotch"]["templates"]=this["hopscotch"]["templates"]||{};this["hopscotch"]["templates"]["bubble_default"]=function(obj){obj||(obj={});var __t,__p='',__e=_.escape,__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}
|
||||
with(obj){function optEscape(str,unsafe){if(unsafe){return _.escape(str);}
|
||||
return str;};__p+='\n<div class="hopscotch-bubble-container" style="width: '+
|
||||
((__t=(step.width))==null?'':__t)+'px; padding: '+
|
||||
((__t=(step.padding))==null?'':__t)+'px;">\n ';if(tour.isTour){;__p+='<span class="hopscotch-bubble-number">'+
|
||||
((__t=(i18n.stepNum))==null?'':__t)+'</span>';};__p+='\n <div class="hopscotch-bubble-content">\n ';if(step.title!==''){;__p+='<h3 class="hopscotch-title">'+
|
||||
((__t=(optEscape(step.title,tour.unsafe)))==null?'':__t)+'</h3>';};__p+='\n ';if(step.content!==''){;__p+='<div class="hopscotch-content">'+
|
||||
((__t=(optEscape(step.content,tour.unsafe)))==null?'':__t)+'</div>';};__p+='\n </div>\n <div class="hopscotch-actions">\n ';if(buttons.showPrev){;__p+='<button class="btn btn-default hopscotch-prev">'+
|
||||
((__t=(i18n.prevBtn))==null?'':__t)+'</button>';};__p+='\n ';if(buttons.showCTA){;__p+='<button class="btn btn-primary hopscotch-cta">'+
|
||||
((__t=(buttons.ctaLabel))==null?'':__t)+'</button>';};__p+='\n ';if(buttons.showNext){;__p+='<button class="btn btn-primary hopscotch-next">'+
|
||||
((__t=(i18n.nextBtn))==null?'':__t)+'</button>';};__p+='\n </div>\n ';if(buttons.showClose){;__p+='<a title="'+
|
||||
((__t=(i18n.closeTooltip))==null?'':__t)+'" href="#" class="hopscotch-bubble-close hopscotch-close"><i class="fa fa-times"></i></a>';};__p+='\n</div>\n<div class="hopscotch-bubble-arrow-container hopscotch-arrow">\n <div class="hopscotch-bubble-arrow-border"></div>\n <div class="hopscotch-bubble-arrow"></div>\n</div>';}
|
||||
return __p};}());}(window,'hopscotch'));
|
||||
6
public/static/js/jquery.drag.min.js
vendored
Normal file
6
public/static/js/jquery.drop.min.js
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/*!
|
||||
* jquery.event.drop - v 2.2
|
||||
* Copyright (c) 2010 Three Dub Media - http://threedubmedia.com
|
||||
* Open Source MIT License - http://threedubmedia.com/code/license
|
||||
*/
|
||||
;(function(d){d.fn.drop=function(i,e,h){var g=typeof i=="string"?i:"",f=d.isFunction(i)?i:d.isFunction(e)?e:null;if(g.indexOf("drop")!==0){g="drop"+g}h=(i==f?e:h)||{};return f?this.bind(g,h,f):this.trigger(g)};d.drop=function(e){e=e||{};b.multi=e.multi===true?Infinity:e.multi===false?1:!isNaN(e.multi)?e.multi:b.multi;b.delay=e.delay||b.delay;b.tolerance=d.isFunction(e.tolerance)?e.tolerance:e.tolerance===null?null:b.tolerance;b.mode=e.mode||b.mode||"intersect"};var c=d.event,a=c.special,b=d.event.special.drop={multi:1,delay:20,mode:"overlap",targets:[],datakey:"dropdata",noBubble:true,add:function(f){var e=d.data(this,b.datakey);e.related+=1},remove:function(){d.data(this,b.datakey).related-=1},setup:function(){if(d.data(this,b.datakey)){return}var e={related:0,active:[],anyactive:0,winner:0,location:{}};d.data(this,b.datakey,e);b.targets.push(this);return false},teardown:function(){var f=d.data(this,b.datakey)||{};if(f.related){return}d.removeData(this,b.datakey);var e=this;b.targets=d.grep(b.targets,function(g){return(g!==e)})},handler:function(g,e){var f,h;if(!e){return}switch(g.type){case"mousedown":case"touchstart":h=d(b.targets);if(typeof e.drop=="string"){h=h.filter(e.drop)}h.each(function(){var i=d.data(this,b.datakey);i.active=[];i.anyactive=0;i.winner=0});e.droppable=h;a.drag.hijack(g,"dropinit",e);break;case"mousemove":case"touchmove":b.event=g;if(!b.timer){b.tolerate(e)}break;case"mouseup":case"touchend":b.timer=clearTimeout(b.timer);if(e.propagates){a.drag.hijack(g,"drop",e);a.drag.hijack(g,"dropend",e)}break}},locate:function(k,h){var l=d.data(k,b.datakey),g=d(k),i=g.offset()||{},e=g.outerHeight(),j=g.outerWidth(),f={elem:k,width:j,height:e,top:i.top,left:i.left,right:i.left+j,bottom:i.top+e};if(l){l.location=f;l.index=h;l.elem=k}return f},contains:function(e,f){return((f[0]||f.left)>=e.left&&(f[0]||f.right)<=e.right&&(f[1]||f.top)>=e.top&&(f[1]||f.bottom)<=e.bottom)},modes:{intersect:function(f,e,g){return this.contains(g,[f.pageX,f.pageY])?1000000000:this.modes.overlap.apply(this,arguments)},overlap:function(f,e,g){return Math.max(0,Math.min(g.bottom,e.bottom)-Math.max(g.top,e.top))*Math.max(0,Math.min(g.right,e.right)-Math.max(g.left,e.left))},fit:function(f,e,g){return this.contains(g,e)?1:0},middle:function(f,e,g){return this.contains(g,[e.left+e.width*0.5,e.top+e.height*0.5])?1:0}},sort:function(f,e){return(e.winner-f.winner)||(f.index-e.index)},tolerate:function(q){var k,e,n,j,l,m,g,p=0,f,h=q.interactions.length,r=[b.event.pageX,b.event.pageY],o=b.tolerance||b.modes[b.mode];do{if(f=q.interactions[p]){if(!f){return}f.drop=[];l=[];m=f.droppable.length;if(o){n=b.locate(f.proxy)}k=0;do{if(g=f.droppable[k]){j=d.data(g,b.datakey);e=j.location;if(!e){continue}j.winner=o?o.call(b,b.event,n,e):b.contains(e,r)?1:0;l.push(j)}}while(++k<m);l.sort(b.sort);k=0;do{if(j=l[k]){if(j.winner&&f.drop.length<b.multi){if(!j.active[p]&&!j.anyactive){if(a.drag.hijack(b.event,"dropstart",q,p,j.elem)[0]!==false){j.active[p]=1;j.anyactive+=1}else{j.winner=0}}if(j.winner){f.drop.push(j.elem)}}else{if(j.active[p]&&j.anyactive==1){a.drag.hijack(b.event,"dropend",q,p,j.elem);j.active[p]=0;j.anyactive-=1}}}}while(++k<m)}}while(++p<h);if(b.last&&r[0]==b.last.pageX&&r[1]==b.last.pageY){delete b.timer}else{b.timer=setTimeout(function(){b.tolerate(q)},b.delay)}b.last=b.event}};a.dropinit=a.dropstart=a.dropend=b})(jQuery);
|
||||
3
public/static/js/require-validator.js
Normal file
@@ -0,0 +1,3 @@
|
||||
define(['validator-core', 'validator-lang'], function (Validator, undefined) {
|
||||
return Validator;
|
||||
});
|
||||
11
public/static/js/sent.js
Normal file
@@ -0,0 +1,11 @@
|
||||
define(['jquery'], function($){
|
||||
var Sent = {
|
||||
|
||||
init: function () {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Sent.init(); //默认初始化执行的代码
|
||||
return Sent;
|
||||
})
|
||||
11944
public/static/js/vue.js
39
public/static/libs/Sortable/.bower.json
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "Sortable",
|
||||
"main": [
|
||||
"Sortable.js"
|
||||
],
|
||||
"homepage": "http://rubaxa.github.io/Sortable/",
|
||||
"authors": [
|
||||
"RubaXa <ibnRubaXa@gmail.com>"
|
||||
],
|
||||
"description": "Minimalist library for reorderable drag-and-drop lists on modern browsers and touch devices. No jQuery.",
|
||||
"keywords": [
|
||||
"sortable",
|
||||
"reorder",
|
||||
"list",
|
||||
"html5",
|
||||
"drag",
|
||||
"and",
|
||||
"drop",
|
||||
"dnd",
|
||||
"web-components"
|
||||
],
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests"
|
||||
],
|
||||
"version": "1.5.1",
|
||||
"_release": "1.5.1",
|
||||
"_resolution": {
|
||||
"type": "version",
|
||||
"tag": "1.5.1",
|
||||
"commit": "c2d48c160cf33d44d167e1b282af103b5bed0edb"
|
||||
},
|
||||
"_source": "https://github.com/RubaXa/Sortable.git",
|
||||
"_target": "~1.5.0",
|
||||
"_originalSource": "Sortable"
|
||||
}
|
||||
12
public/static/libs/Sortable/.editorconfig
Normal file
@@ -0,0 +1,12 @@
|
||||
# editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = tab
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
5
public/static/libs/Sortable/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
node_modules
|
||||
mock.png
|
||||
.*.sw*
|
||||
.build*
|
||||
jquery.fn.*
|
||||
24
public/static/libs/Sortable/.jshintrc
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"strict": true,
|
||||
"newcap": false,
|
||||
"node": true,
|
||||
"expr": true,
|
||||
"supernew": true,
|
||||
"laxbreak": true,
|
||||
"white": true,
|
||||
"globals": {
|
||||
"define": true,
|
||||
"test": true,
|
||||
"expect": true,
|
||||
"module": true,
|
||||
"asyncTest": true,
|
||||
"start": true,
|
||||
"ok": true,
|
||||
"equal": true,
|
||||
"notEqual": true,
|
||||
"deepEqual": true,
|
||||
"window": true,
|
||||
"document": true,
|
||||
"performance": true
|
||||
}
|
||||
}
|
||||
23
public/static/libs/Sortable/CONTRIBUTING.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# Contribution Guidelines
|
||||
|
||||
### Issue
|
||||
|
||||
1. Try [dev](https://github.com/RubaXa/Sortable/tree/dev/)-branch, perhaps the problem has been solved;
|
||||
2. [Use the search](https://github.com/RubaXa/Sortable/search?type=Issues&q=problem), maybe already have an answer;
|
||||
3. If not found, create example on [jsbin.com (draft)](http://jsbin.com/zunibaxada/1/edit?html,js,output) and describe the problem.
|
||||
|
||||
---
|
||||
|
||||
### Pull Request
|
||||
|
||||
1. Before PR run `grunt`;
|
||||
2. Only into [dev](https://github.com/RubaXa/Sortable/tree/dev/)-branch.
|
||||
|
||||
### Setup
|
||||
|
||||
Pieced together from [gruntjs](http://gruntjs.com/getting-started)
|
||||
|
||||
1. Fork repo on [github](https://github.com)
|
||||
2. Clone locally
|
||||
3. from local repro ```npm install```
|
||||
4. Install grunt-cli globally ```sudo -H npm install -g grunt-cli```
|
||||
88
public/static/libs/Sortable/Gruntfile.js
Normal file
@@ -0,0 +1,88 @@
|
||||
module.exports = function (grunt) {
|
||||
'use strict';
|
||||
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
|
||||
version: {
|
||||
js: {
|
||||
src: ['<%= pkg.exportName %>.js', '*.json']
|
||||
},
|
||||
cdn: {
|
||||
options: {
|
||||
prefix: '(cdnjs\\.cloudflare\\.com\\/ajax\\/libs\\/Sortable|cdn\\.jsdelivr\\.net\\/sortable)\\/',
|
||||
replace: '[0-9\\.]+'
|
||||
},
|
||||
src: ['README.md']
|
||||
}
|
||||
},
|
||||
|
||||
jshint: {
|
||||
all: ['*.js', '!*.min.js'],
|
||||
|
||||
options: {
|
||||
jshintrc: true
|
||||
}
|
||||
},
|
||||
|
||||
uglify: {
|
||||
options: {
|
||||
banner: '/*! <%= pkg.exportName %> <%= pkg.version %> - <%= pkg.license %> | <%= pkg.repository.url %> */\n'
|
||||
},
|
||||
dist: {
|
||||
files: {
|
||||
'<%= pkg.exportName %>.min.js': ['<%= pkg.exportName %>.js']
|
||||
}
|
||||
},
|
||||
jquery: {
|
||||
files: {}
|
||||
}
|
||||
},
|
||||
|
||||
jquery: {}
|
||||
});
|
||||
|
||||
|
||||
grunt.registerTask('jquery', function (exportName, uglify) {
|
||||
if (exportName == 'min') {
|
||||
exportName = null;
|
||||
uglify = 'min';
|
||||
}
|
||||
|
||||
if (!exportName) {
|
||||
exportName = 'sortable';
|
||||
}
|
||||
|
||||
var fs = require('fs'),
|
||||
filename = 'jquery.fn.' + exportName + '.js';
|
||||
|
||||
grunt.log.oklns(filename);
|
||||
|
||||
fs.writeFileSync(
|
||||
filename,
|
||||
(fs.readFileSync('jquery.binding.js') + '')
|
||||
.replace('$.fn.sortable', '$.fn.' + exportName)
|
||||
.replace('/* CODE */',
|
||||
(fs.readFileSync('Sortable.js') + '')
|
||||
.replace(/^[\s\S]*?function[\s\S]*?(var[\s\S]+)\/\/\s+Export[\s\S]+/, '$1')
|
||||
)
|
||||
);
|
||||
|
||||
if (uglify) {
|
||||
var opts = {};
|
||||
|
||||
opts['jquery.fn.' + exportName + '.min.js'] = filename;
|
||||
grunt.config.set('uglify.jquery.files', opts);
|
||||
|
||||
grunt.task.run('uglify:jquery');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
grunt.loadNpmTasks('grunt-version');
|
||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
||||
grunt.loadNpmTasks('grunt-contrib-uglify');
|
||||
|
||||
grunt.registerTask('tests', ['jshint']);
|
||||
grunt.registerTask('default', ['tests', 'version', 'uglify:dist']);
|
||||
};
|
||||
17
public/static/libs/Sortable/ISSUE_TEMPLATE.md
Normal file
@@ -0,0 +1,17 @@
|
||||
Before you create a issue, check it:
|
||||
|
||||
1. Try [master](https://github.com/RubaXa/Sortable/tree/master/)-branch, perhaps the problem has been solved;
|
||||
2. [Use the search](https://github.com/RubaXa/Sortable/search?q=problem), maybe already have an answer;
|
||||
3. If not found, create example on [jsbin.com (draft)](http://jsbin.com/vojixek/edit?html,js,output) and describe the problem.
|
||||
|
||||
Bindings:
|
||||
- Angular
|
||||
- 2.0+: https://github.com/SortableJS/angular-sortablejs/issues
|
||||
- legacy: https://github.com/SortableJS/angular-legacy-sortablejs/issues
|
||||
- React
|
||||
- ES2015+: https://github.com/SortableJS/react-sortablejs/issues
|
||||
- mixin: https://github.com/SortableJS/react-mixin-sortablejs/issues
|
||||
- Polymer: https://github.com/SortableJS/polymer-sortablejs/issues
|
||||
- Knockout: https://github.com/SortableJS/knockout-sortablejs/issues
|
||||
- Meteor: https://github.com/SortableJS/meteor-sortablejs/issues
|
||||
|
||||
640
public/static/libs/Sortable/README.md
Normal file
@@ -0,0 +1,640 @@
|
||||
# Sortable
|
||||
Sortable is a <s>minimalist</s> JavaScript library for reorderable drag-and-drop lists.
|
||||
|
||||
Demo: http://rubaxa.github.io/Sortable/
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
* Supports touch devices and [modern](http://caniuse.com/#search=drag) browsers (including IE9)
|
||||
* Can drag from one list to another or within the same list
|
||||
* CSS animation when moving items
|
||||
* Supports drag handles *and selectable text* (better than voidberg's html5sortable)
|
||||
* Smart auto-scrolling
|
||||
* Built using native HTML5 drag and drop API
|
||||
* Supports
|
||||
* [Meteor](https://github.com/SortableJS/meteor-sortablejs)
|
||||
* AngularJS
|
||||
* [2.0+](https://github.com/SortableJS/angular-sortablejs)
|
||||
* [1.*](https://github.com/SortableJS/angular-legacy-sortablejs)
|
||||
* React
|
||||
* [ES2015+](https://github.com/SortableJS/react-sortablejs)
|
||||
* [Mixin](https://github.com/SortableJS/react-mixin-sortablejs)
|
||||
* [Knockout](https://github.com/SortableJS/knockout-sortablejs)
|
||||
* [Polymer](https://github.com/SortableJS/polymer-sortablejs)
|
||||
* [Vue](https://github.com/SortableJS/Vue.Draggable)
|
||||
* Supports any CSS library, e.g. [Bootstrap](#bs)
|
||||
* Simple API
|
||||
* [CDN](#cdn)
|
||||
* No jQuery (but there is [support](#jq))
|
||||
|
||||
|
||||
<br/>
|
||||
|
||||
|
||||
### Articles
|
||||
|
||||
* [Sortable v1.0 — New capabilities](https://github.com/RubaXa/Sortable/wiki/Sortable-v1.0-—-New-capabilities/) (December 22, 2014)
|
||||
* [Sorting with the help of HTML5 Drag'n'Drop API](https://github.com/RubaXa/Sortable/wiki/Sorting-with-the-help-of-HTML5-Drag'n'Drop-API/) (December 23, 2013)
|
||||
|
||||
|
||||
<br/>
|
||||
|
||||
### Install
|
||||
|
||||
Via npm
|
||||
|
||||
```bash
|
||||
$ npm install sortablejs --save
|
||||
```
|
||||
|
||||
Via bower:
|
||||
|
||||
```bash
|
||||
$ bower install --save sortablejs
|
||||
```
|
||||
|
||||
<br/>
|
||||
|
||||
### Usage
|
||||
```html
|
||||
<ul id="items">
|
||||
<li>item 1</li>
|
||||
<li>item 2</li>
|
||||
<li>item 3</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
```js
|
||||
var el = document.getElementById('items');
|
||||
var sortable = Sortable.create(el);
|
||||
```
|
||||
|
||||
You can use any element for the list and its elements, not just `ul`/`li`. Here is an [example with `div`s](http://jsbin.com/qumuwe/edit?html,js,output).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
### Options
|
||||
```js
|
||||
var sortable = new Sortable(el, {
|
||||
group: "name", // or { name: "...", pull: [true, false, clone], put: [true, false, array] }
|
||||
sort: true, // sorting inside list
|
||||
delay: 0, // time in milliseconds to define when the sorting should start
|
||||
disabled: false, // Disables the sortable if set to true.
|
||||
store: null, // @see Store
|
||||
animation: 150, // ms, animation speed moving items when sorting, `0` — without animation
|
||||
handle: ".my-handle", // Drag handle selector within list items
|
||||
filter: ".ignore-elements", // Selectors that do not lead to dragging (String or Function)
|
||||
preventOnFilter: true, // Call `event.preventDefault()` when triggered `filter`
|
||||
draggable: ".item", // Specifies which items inside the element should be draggable
|
||||
ghostClass: "sortable-ghost", // Class name for the drop placeholder
|
||||
chosenClass: "sortable-chosen", // Class name for the chosen item
|
||||
dragClass: "sortable-drag", // Class name for the dragging item
|
||||
dataIdAttr: 'data-id',
|
||||
|
||||
forceFallback: false, // ignore the HTML5 DnD behaviour and force the fallback to kick in
|
||||
|
||||
fallbackClass: "sortable-fallback", // Class name for the cloned DOM Element when using forceFallback
|
||||
fallbackOnBody: false, // Appends the cloned DOM Element into the Document's Body
|
||||
fallbackTolerance: 0, // Specify in pixels how far the mouse should move before it's considered as a drag.
|
||||
|
||||
scroll: true, // or HTMLElement
|
||||
scrollFn: function(offsetX, offsetY, originalEvent) { ... }, // if you have custom scrollbar scrollFn may be used for autoscrolling
|
||||
scrollSensitivity: 30, // px, how near the mouse must be to an edge to start scrolling.
|
||||
scrollSpeed: 10, // px
|
||||
|
||||
setData: function (/** DataTransfer */dataTransfer, /** HTMLElement*/dragEl) {
|
||||
dataTransfer.setData('Text', dragEl.textContent); // `dataTransfer` object of HTML5 DragEvent
|
||||
},
|
||||
|
||||
// Element is chosen
|
||||
onChoose: function (/**Event*/evt) {
|
||||
evt.oldIndex; // element index within parent
|
||||
},
|
||||
|
||||
// Element dragging started
|
||||
onStart: function (/**Event*/evt) {
|
||||
evt.oldIndex; // element index within parent
|
||||
},
|
||||
|
||||
// Element dragging ended
|
||||
onEnd: function (/**Event*/evt) {
|
||||
evt.oldIndex; // element's old index within parent
|
||||
evt.newIndex; // element's new index within parent
|
||||
},
|
||||
|
||||
// Element is dropped into the list from another list
|
||||
onAdd: function (/**Event*/evt) {
|
||||
var itemEl = evt.item; // dragged HTMLElement
|
||||
evt.from; // previous list
|
||||
// + indexes from onEnd
|
||||
},
|
||||
|
||||
// Changed sorting within list
|
||||
onUpdate: function (/**Event*/evt) {
|
||||
var itemEl = evt.item; // dragged HTMLElement
|
||||
// + indexes from onEnd
|
||||
},
|
||||
|
||||
// Called by any change to the list (add / update / remove)
|
||||
onSort: function (/**Event*/evt) {
|
||||
// same properties as onUpdate
|
||||
},
|
||||
|
||||
// Element is removed from the list into another list
|
||||
onRemove: function (/**Event*/evt) {
|
||||
// same properties as onUpdate
|
||||
},
|
||||
|
||||
// Attempt to drag a filtered element
|
||||
onFilter: function (/**Event*/evt) {
|
||||
var itemEl = evt.item; // HTMLElement receiving the `mousedown|tapstart` event.
|
||||
},
|
||||
|
||||
// Event when you move an item in the list or between lists
|
||||
onMove: function (/**Event*/evt, /**Event*/originalEvent) {
|
||||
// Example: http://jsbin.com/tuyafe/1/edit?js,output
|
||||
evt.dragged; // dragged HTMLElement
|
||||
evt.draggedRect; // TextRectangle {left, top, right и bottom}
|
||||
evt.related; // HTMLElement on which have guided
|
||||
evt.relatedRect; // TextRectangle
|
||||
originalEvent.clientY; // mouse position
|
||||
// return false; — for cancel
|
||||
},
|
||||
|
||||
// Called when creating a clone of element
|
||||
onClone: function (/**Event*/evt) {
|
||||
var origEl = evt.item;
|
||||
var cloneEl = evt.clone;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
#### `group` option
|
||||
To drag elements from one list into another, both lists must have the same `group` value.
|
||||
You can also define whether lists can give away, give and keep a copy (`clone`), and receive elements.
|
||||
|
||||
* name: `String` — group name
|
||||
* pull: `true|false|'clone'|function` — ability to move from the list. `clone` — copy the item, rather than move.
|
||||
* put: `true|false|["foo", "bar"]|function` — whether elements can be added from other lists, or an array of group names from which elements can be taken.
|
||||
* revertClone: `boolean` — revert cloned element to initial position after moving to a another list.
|
||||
|
||||
|
||||
Demo:
|
||||
- http://jsbin.com/naduvo/edit?js,output
|
||||
- http://jsbin.com/rusuvot/edit?js,output — use of complex logic in the `pull` and` put`
|
||||
- http://jsbin.com/magogub/edit?js,output — use `revertClone: true`
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
#### `sort` option
|
||||
Sorting inside list.
|
||||
|
||||
Demo: http://jsbin.com/videzob/edit?html,js,output
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
#### `delay` option
|
||||
Time in milliseconds to define when the sorting should start.
|
||||
|
||||
Demo: http://jsbin.com/xizeh/edit?html,js,output
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
#### `disabled` options
|
||||
Disables the sortable if set to `true`.
|
||||
|
||||
Demo: http://jsbin.com/xiloqu/edit?html,js,output
|
||||
|
||||
```js
|
||||
var sortable = Sortable.create(list);
|
||||
|
||||
document.getElementById("switcher").onclick = function () {
|
||||
var state = sortable.option("disabled"); // get
|
||||
|
||||
sortable.option("disabled", !state); // set
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
#### `handle` option
|
||||
To make list items draggable, Sortable disables text selection by the user.
|
||||
That's not always desirable. To allow text selection, define a drag handler,
|
||||
which is an area of every list element that allows it to be dragged around.
|
||||
|
||||
Demo: http://jsbin.com/newize/edit?html,js,output
|
||||
|
||||
```js
|
||||
Sortable.create(el, {
|
||||
handle: ".my-handle"
|
||||
});
|
||||
```
|
||||
|
||||
```html
|
||||
<ul>
|
||||
<li><span class="my-handle">::</span> list item text one
|
||||
<li><span class="my-handle">::</span> list item text two
|
||||
</ul>
|
||||
```
|
||||
|
||||
```css
|
||||
.my-handle {
|
||||
cursor: move;
|
||||
cursor: -webkit-grabbing;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
#### `filter` option
|
||||
|
||||
|
||||
```js
|
||||
Sortable.create(list, {
|
||||
filter: ".js-remove, .js-edit",
|
||||
onFilter: function (evt) {
|
||||
var item = evt.item,
|
||||
ctrl = evt.target;
|
||||
|
||||
if (Sortable.utils.is(ctrl, ".js-remove")) { // Click on remove button
|
||||
item.parentNode.removeChild(item); // remove sortable item
|
||||
}
|
||||
else if (Sortable.utils.is(ctrl, ".js-edit")) { // Click on edit link
|
||||
// ...
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
#### `ghostClass` option
|
||||
Class name for the drop placeholder (default `sortable-ghost`).
|
||||
|
||||
Demo: http://jsbin.com/hunifu/4/edit?css,js,output
|
||||
|
||||
```css
|
||||
.ghost {
|
||||
opacity: 0.4;
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
Sortable.create(list, {
|
||||
ghostClass: "ghost"
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
#### `chosenClass` option
|
||||
Class name for the chosen item (default `sortable-chosen`).
|
||||
|
||||
Demo: http://jsbin.com/hunifu/3/edit?html,css,js,output
|
||||
|
||||
```css
|
||||
.chosen {
|
||||
color: #fff;
|
||||
background-color: #c00;
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
Sortable.create(list, {
|
||||
delay: 500,
|
||||
chosenClass: "chosen"
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
#### `forceFallback` option
|
||||
If set to `true`, the Fallback for non HTML5 Browser will be used, even if we are using an HTML5 Browser.
|
||||
This gives us the possibility to test the behaviour for older Browsers even in newer Browser, or make the Drag 'n Drop feel more consistent between Desktop , Mobile and old Browsers.
|
||||
|
||||
On top of that, the Fallback always generates a copy of that DOM Element and appends the class `fallbackClass` defined in the options. This behaviour controls the look of this 'dragged' Element.
|
||||
|
||||
Demo: http://jsbin.com/yacuqib/edit?html,css,js,output
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
#### `fallbackTolerance` option
|
||||
Emulates the native drag threshold. Specify in pixels how far the mouse should move before it's considered as a drag.
|
||||
Useful if the items are also clickable like in a list of links.
|
||||
|
||||
When the user clicks inside a sortable element, it's not uncommon for your hand to move a little between the time you press and the time you release.
|
||||
Dragging only starts if you move the pointer past a certain tolerance, so that you don't accidentally start dragging every time you click.
|
||||
|
||||
3 to 5 are probably good values.
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
#### `scroll` option
|
||||
If set to `true`, the page (or sortable-area) scrolls when coming to an edge.
|
||||
|
||||
Demo:
|
||||
- `window`: http://jsbin.com/tutuzeh/edit?html,js,output
|
||||
- `overflow: hidden`: http://jsbin.com/kolisu/edit?html,js,output
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
#### `scrollFn` option
|
||||
Defines function that will be used for autoscrolling. el.scrollTop/el.scrollLeft is used by default.
|
||||
Useful when you have custom scrollbar with dedicated scroll function.
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
#### `scrollSensitivity` option
|
||||
Defines how near the mouse must be to an edge to start scrolling.
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
#### `scrollSpeed` option
|
||||
The speed at which the window should scroll once the mouse pointer gets within the `scrollSensitivity` distance.
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
### Event object ([demo](http://jsbin.com/xedusu/edit?js,output))
|
||||
|
||||
- to:`HTMLElement` — list, in which moved element.
|
||||
- from:`HTMLElement` — previous list
|
||||
- item:`HTMLElement` — dragged element
|
||||
- clone:`HTMLElement`
|
||||
- oldIndex:`Number|undefined` — old index within parent
|
||||
- newIndex:`Number|undefined` — new index within parent
|
||||
|
||||
|
||||
#### `move` event object
|
||||
- to:`HTMLElement`
|
||||
- from:`HTMLElement`
|
||||
- dragged:`HTMLElement`
|
||||
- draggedRect:` TextRectangle`
|
||||
- related:`HTMLElement` — element on which have guided
|
||||
- relatedRect:` TextRectangle`
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
### Method
|
||||
|
||||
|
||||
##### option(name:`String`[, value:`*`]):`*`
|
||||
Get or set the option.
|
||||
|
||||
|
||||
|
||||
##### closest(el:`String`[, selector:`HTMLElement`]):`HTMLElement|null`
|
||||
For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.
|
||||
|
||||
|
||||
##### toArray():`String[]`
|
||||
Serializes the sortable's item `data-id`'s (`dataIdAttr` option) into an array of string.
|
||||
|
||||
|
||||
##### sort(order:`String[]`)
|
||||
Sorts the elements according to the array.
|
||||
|
||||
```js
|
||||
var order = sortable.toArray();
|
||||
sortable.sort(order.reverse()); // apply
|
||||
```
|
||||
|
||||
|
||||
##### save()
|
||||
Save the current sorting (see [store](#store))
|
||||
|
||||
|
||||
##### destroy()
|
||||
Removes the sortable functionality completely.
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
<a name="store"></a>
|
||||
### Store
|
||||
Saving and restoring of the sort.
|
||||
|
||||
```html
|
||||
<ul>
|
||||
<li data-id="1">order</li>
|
||||
<li data-id="2">save</li>
|
||||
<li data-id="3">restore</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
```js
|
||||
Sortable.create(el, {
|
||||
group: "localStorage-example",
|
||||
store: {
|
||||
/**
|
||||
* Get the order of elements. Called once during initialization.
|
||||
* @param {Sortable} sortable
|
||||
* @returns {Array}
|
||||
*/
|
||||
get: function (sortable) {
|
||||
var order = localStorage.getItem(sortable.options.group.name);
|
||||
return order ? order.split('|') : [];
|
||||
},
|
||||
|
||||
/**
|
||||
* Save the order of elements. Called onEnd (when the item is dropped).
|
||||
* @param {Sortable} sortable
|
||||
*/
|
||||
set: function (sortable) {
|
||||
var order = sortable.toArray();
|
||||
localStorage.setItem(sortable.options.group.name, order.join('|'));
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
<a name="bs"></a>
|
||||
### Bootstrap
|
||||
Demo: http://jsbin.com/qumuwe/edit?html,js,output
|
||||
|
||||
```html
|
||||
<!-- Latest compiled and minified CSS -->
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css"/>
|
||||
|
||||
|
||||
<!-- Latest Sortable -->
|
||||
<script src="http://rubaxa.github.io/Sortable/Sortable.js"></script>
|
||||
|
||||
|
||||
<!-- Simple List -->
|
||||
<ul id="simpleList" class="list-group">
|
||||
<li class="list-group-item">This is <a href="http://rubaxa.github.io/Sortable/">Sortable</a></li>
|
||||
<li class="list-group-item">It works with Bootstrap...</li>
|
||||
<li class="list-group-item">...out of the box.</li>
|
||||
<li class="list-group-item">It has support for touch devices.</li>
|
||||
<li class="list-group-item">Just drag some elements around.</li>
|
||||
</ul>
|
||||
|
||||
<script>
|
||||
// Simple list
|
||||
Sortable.create(simpleList, { /* options */ });
|
||||
</script>
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
### Static methods & properties
|
||||
|
||||
|
||||
|
||||
##### Sortable.create(el:`HTMLElement`[, options:`Object`]):`Sortable`
|
||||
Create new instance.
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
##### Sortable.active:`Sortable`
|
||||
Link to the active instance.
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
##### Sortable.utils
|
||||
* on(el`:HTMLElement`, event`:String`, fn`:Function`) — attach an event handler function
|
||||
* off(el`:HTMLElement`, event`:String`, fn`:Function`) — remove an event handler
|
||||
* css(el`:HTMLElement`)`:Object` — get the values of all the CSS properties
|
||||
* css(el`:HTMLElement`, prop`:String`)`:Mixed` — get the value of style properties
|
||||
* css(el`:HTMLElement`, prop`:String`, value`:String`) — set one CSS properties
|
||||
* css(el`:HTMLElement`, props`:Object`) — set more CSS properties
|
||||
* find(ctx`:HTMLElement`, tagName`:String`[, iterator`:Function`])`:Array` — get elements by tag name
|
||||
* bind(ctx`:Mixed`, fn`:Function`)`:Function` — Takes a function and returns a new one that will always have a particular context
|
||||
* is(el`:HTMLElement`, selector`:String`)`:Boolean` — check the current matched set of elements against a selector
|
||||
* closest(el`:HTMLElement`, selector`:String`[, ctx`:HTMLElement`])`:HTMLElement|Null` — for each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree
|
||||
* clone(el`:HTMLElement`)`:HTMLElement` — create a deep copy of the set of matched elements
|
||||
* toggleClass(el`:HTMLElement`, name`:String`, state`:Boolean`) — add or remove one classes from each element
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
<a name="cdn"></a>
|
||||
### CDN
|
||||
|
||||
```html
|
||||
<!-- CDNJS :: Sortable (https://cdnjs.com/) -->
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/Sortable/1.5.1/Sortable.min.js"></script>
|
||||
|
||||
|
||||
<!-- jsDelivr :: Sortable (http://www.jsdelivr.com/) -->
|
||||
<script src="//cdn.jsdelivr.net/sortable/1.5.1/Sortable.min.js"></script>
|
||||
|
||||
|
||||
<!-- jsDelivr :: Sortable :: Latest (http://www.jsdelivr.com/) -->
|
||||
<script src="//cdn.jsdelivr.net/sortable/latest/Sortable.min.js"></script>
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
<a name="jq"></a>
|
||||
### jQuery compatibility
|
||||
To assemble plugin for jQuery, perform the following steps:
|
||||
|
||||
```bash
|
||||
cd Sortable
|
||||
npm install
|
||||
grunt jquery
|
||||
```
|
||||
|
||||
Now you can use `jquery.fn.sortable.js`:<br/>
|
||||
(or `jquery.fn.sortable.min.js` if you run `grunt jquery:min`)
|
||||
|
||||
```js
|
||||
$("#list").sortable({ /* options */ }); // init
|
||||
|
||||
$("#list").sortable("widget"); // get Sortable instance
|
||||
|
||||
$("#list").sortable("destroy"); // destroy Sortable instance
|
||||
|
||||
$("#list").sortable("{method-name}"); // call an instance method
|
||||
|
||||
$("#list").sortable("{method-name}", "foo", "bar"); // call an instance method with parameters
|
||||
```
|
||||
|
||||
And `grunt jquery:mySortableFunc` → `jquery.fn.mySortableFunc.js`
|
||||
|
||||
---
|
||||
|
||||
|
||||
### Contributing (Issue/PR)
|
||||
|
||||
Please, [read this](CONTRIBUTING.md).
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## MIT LICENSE
|
||||
Copyright 2013-2017 Lebedev Konstantin <ibnRubaXa@gmail.com>
|
||||
http://rubaxa.github.io/Sortable/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
1481
public/static/libs/Sortable/Sortable.js
Normal file
2
public/static/libs/Sortable/Sortable.min.js
vendored
Normal file
29
public/static/libs/Sortable/bower.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "Sortable",
|
||||
"main": [
|
||||
"Sortable.js"
|
||||
],
|
||||
"homepage": "http://rubaxa.github.io/Sortable/",
|
||||
"authors": [
|
||||
"RubaXa <ibnRubaXa@gmail.com>"
|
||||
],
|
||||
"description": "Minimalist library for reorderable drag-and-drop lists on modern browsers and touch devices. No jQuery.",
|
||||
"keywords": [
|
||||
"sortable",
|
||||
"reorder",
|
||||
"list",
|
||||
"html5",
|
||||
"drag",
|
||||
"and",
|
||||
"drop",
|
||||
"dnd",
|
||||
"web-components"
|
||||
],
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests"
|
||||
]
|
||||
}
|
||||
32
public/static/libs/Sortable/component.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "Sortable",
|
||||
"main": "Sortable.js",
|
||||
"version": "1.5.1",
|
||||
"homepage": "http://rubaxa.github.io/Sortable/",
|
||||
"repo": "RubaXa/Sortable",
|
||||
"authors": [
|
||||
"RubaXa <ibnRubaXa@gmail.com>"
|
||||
],
|
||||
"description": "Minimalist library for reorderable drag-and-drop lists on modern browsers and touch devices. No jQuery.",
|
||||
"keywords": [
|
||||
"sortable",
|
||||
"reorder",
|
||||
"list",
|
||||
"html5",
|
||||
"drag",
|
||||
"and",
|
||||
"drop",
|
||||
"dnd"
|
||||
],
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests"
|
||||
],
|
||||
|
||||
"scripts": [
|
||||
"Sortable.js"
|
||||
]
|
||||
}
|
||||
344
public/static/libs/Sortable/index.html
Normal file
@@ -0,0 +1,344 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta property="og:image" content="/st/og-image.png"/>
|
||||
|
||||
<title>Sortable. No jQuery.</title>
|
||||
|
||||
<meta name="keywords" content="sortable, reorder, list, javascript, html5, drag and drop, dnd, animation, groups, angular, ng-sortable, react, mixin, effects, rubaxa"/>
|
||||
<meta name="description" content="Sortable - is a minimalist JavaScript library for reorderable drag-and-drop lists on modern browsers and touch devices. No jQuery. Supports Meteor, AngularJS, React and any CSS library, e.g. Bootstrap."/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=0.5"/>
|
||||
|
||||
<link href="//rubaxa.github.io/Ply/ply.css" rel="stylesheet" type="text/css"/>
|
||||
<link href="//fonts.googleapis.com/css?family=Roboto:300" rel="stylesheet" type="text/css"/>
|
||||
|
||||
<link href="st/app.css" rel="stylesheet" type="text/css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<a href="https://github.com/RubaXa/Sortable"><img style="position: fixed; top: 0; right: 0; border: 0; z-index: 10000;" src="//s3.amazonaws.com/github/ribbons/forkme_right_orange_ff7600.png" alt="Fork me on GitHub"></a>
|
||||
|
||||
<div class="container">
|
||||
<div style="padding: 80px 150px 0; height: 160px;">
|
||||
<a class="logo" href="https://github.com/RubaXa/Sortable"><img src="st/logo.png"/></a>
|
||||
<h1 data-force="40" data-force-y="2.5">The JavaScript library for modern browsers and touch devices. No jQuery.</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Connected lists -->
|
||||
<div class="container" style="height: 520px">
|
||||
<div data-force="30" class="layer block" style="left: 14.5%; top: 0; width: 37%">
|
||||
<div class="layer title">List A</div>
|
||||
<ul id="foo" class="block__list block__list_words">
|
||||
<li>бегемот</li>
|
||||
<li>корм</li>
|
||||
<li>антон</li>
|
||||
<li>сало</li>
|
||||
<li>железосталь</li>
|
||||
<li>валик</li>
|
||||
<li>кровать</li>
|
||||
<li>краб</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div data-force="18" class="layer block" style="left: 58%; top: 143px; width: 40%;">
|
||||
<div class="layer title">List B</div>
|
||||
<ul id="bar" class="block__list block__list_tags">
|
||||
<li>казнить</li>
|
||||
<li>,</li>
|
||||
<li>нельзя</li>
|
||||
<li>помиловать</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Multi connected lists -->
|
||||
<a name="m"></a>
|
||||
<div class="container">
|
||||
<div id="multi" style="margin-left: 30px">
|
||||
<div><div data-force="5" class="layer title title_xl">Multi</div></div>
|
||||
|
||||
<div class="layer tile" data-force="30">
|
||||
<div class="tile__name">Group A</div>
|
||||
<div class="tile__list">
|
||||
<img src="st/face-01.jpg"/><!--
|
||||
--><img src="st/face-02.jpg"/><!--
|
||||
--><img src="st/face-03.jpg"/><!--
|
||||
--><img src="st/face-04.jpg"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layer tile" data-force="25">
|
||||
<div class="tile__name">Group B</div>
|
||||
<div class="tile__list">
|
||||
<img src="st/face-05.jpg"/><!--
|
||||
--><img src="st/face-06.jpg"/><!--
|
||||
--><img src="st/face-07.jpg"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layer tile" data-force="20">
|
||||
<div class="tile__name">Group C</div>
|
||||
<div class="tile__list">
|
||||
<img src="st/face-08.jpg"/><!--
|
||||
--><img src="st/face-09.jpg"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Editable list -->
|
||||
<a name="e"></a>
|
||||
<div class="container" style="margin-top: 100px">
|
||||
<div id="filter" style="margin-left: 30px">
|
||||
<div><div data-force="5" class="layer title title_xl">Editable list</div></div>
|
||||
|
||||
<div style="margin-top: -8px; margin-left: 10px" class="block__list block__list_words">
|
||||
<ul id="editable">
|
||||
<li>Оля<i class="js-remove">✖</i></li>
|
||||
<li>Владимир<i class="js-remove">✖</i></li>
|
||||
<li>Алина<i class="js-remove">✖</i></li>
|
||||
</ul>
|
||||
|
||||
<button id="addUser">Add</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Advanced connected lists -->
|
||||
<a name="ag"></a>
|
||||
<div class="container" style="margin-top: 100px;">
|
||||
<div id="advanced" style="margin-left: 30px;">
|
||||
<div><div data-force="5" class="layer title title_xl">Advanced groups</div></div>
|
||||
|
||||
<div style="width: 25%; float: left; margin-top: 15px; margin-left: 10px" class="block__list block__list_words">
|
||||
<div class="block__list-title">pull & put</div>
|
||||
<ul id="advanced-1">
|
||||
<li>Meat</li>
|
||||
<li>Potato</li>
|
||||
<li>Tea</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div style="width: 25%; float: left; margin-top: 15px; margin-left: 10px" class="block__list block__list_words">
|
||||
<div class="block__list-title">only pull (clone) no reordering</div>
|
||||
<ul id="advanced-2">
|
||||
<li>Sex</li>
|
||||
<li>Drugs</li>
|
||||
<li>Rock'n'roll</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div style="width: 25%; float: left; margin-top: 15px; margin-left: 10px" class="block__list block__list_words">
|
||||
<div class="block__list-title">only put</div>
|
||||
<ul id="advanced-3">
|
||||
<li>Money</li>
|
||||
<li>Force</li>
|
||||
<li>Agility</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div style="clear: both"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 'handle' option -->
|
||||
<a name="h"></a>
|
||||
<div class="container" style="margin-top: 100px;">
|
||||
<div id="handle" style="margin-left: 30px;">
|
||||
<div><div data-force="5" class="layer title title_xl">Drag handle and selectable text</div></div>
|
||||
|
||||
<div style="width: 30%; margin-left: 10px" class="block__list_words">
|
||||
<ul id="handle-1">
|
||||
<li><span class="drag-handle">☰</span>Select text freely</li>
|
||||
<li><span class="drag-handle">☰</span>Drag my handle</li>
|
||||
<li><span class="drag-handle">☰</span>Best of both worlds</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div style="clear: both"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Angular -->
|
||||
<a name="ng"></a>
|
||||
<div id="todos" ng-app="todoApp" class="container" style="margin-top: 100px">
|
||||
<div style="margin-left: 30px">
|
||||
<div><div data-force="5" class="layer title title_xl">AngularJS / ng-sortable</div></div>
|
||||
|
||||
<div style="width: 30%; margin-top: -8px; margin-left: 10px; float: left;" class="block__list block__list_words">
|
||||
<div ng-controller="TodoController">
|
||||
<span style="padding-left: 20px">{{remaining()}} of {{todos.length}} remaining</span>
|
||||
[ <a href="" ng-click="archive()">archive</a> ]
|
||||
<ul ng-sortable="{ group: 'todo', animation: 150 }" class="unstyled">
|
||||
<li ng-repeat="todo in todos">
|
||||
<input type="checkbox" ng-model="todo.done">
|
||||
<span class="done-{{todo.done}}">{{todo.text}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<form ng-submit="addTodo()" style="padding-left: 20px">
|
||||
<input type="text" ng-model="todoText" size="30"
|
||||
placeholder="add new todo here">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div style="width: 30%; margin-top: -8px; margin-left: 10px; float: left;" class="block__list block__list_words">
|
||||
<div ng-controller="TodoControllerNext">
|
||||
<span style="padding-left: 20px">{{remaining()}} of {{todos.length}} remaining</span>
|
||||
<ul ng-sortable="sortableConfig" class="unstyled">
|
||||
<li ng-repeat="todo in todos">
|
||||
<input type="checkbox" ng-model="todo.done">
|
||||
<span class="done-{{todo.done}}">{{todo.text}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="clear: both"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Code example -->
|
||||
<a name="c"></a>
|
||||
<div class="container" style="margin-top: 100px">
|
||||
<div style="margin-left: 30px">
|
||||
<div><div class="layer title title_xl">Code example</div></div>
|
||||
<pre data-force="100" class="layer javascript" style="margin-top: -8px; margin-left: 10px; width: 90%"><code>// Simple list
|
||||
var list = document.getElementById("my-ui-list");
|
||||
Sortable.create(list); // That's all.
|
||||
|
||||
|
||||
// Grouping
|
||||
var foo = document.getElementById("foo");
|
||||
Sortable.create(foo, { group: "omega" });
|
||||
|
||||
var bar = document.getElementById("bar");
|
||||
Sortable.create(bar, { group: "omega" });
|
||||
|
||||
|
||||
// Or
|
||||
var container = document.getElementById("multi");
|
||||
var sort = Sortable.create(container, {
|
||||
animation: 150, // ms, animation speed moving items when sorting, `0` — without animation
|
||||
handle: ".tile__title", // Restricts sort start click/touch to the specified element
|
||||
draggable: ".tile", // Specifies which items inside the element should be sortable
|
||||
onUpdate: function (evt/**Event*/){
|
||||
var item = evt.item; // the current dragged HTMLElement
|
||||
}
|
||||
});
|
||||
|
||||
// ..
|
||||
sort.destroy();
|
||||
|
||||
|
||||
// Editable list
|
||||
var editableList = Sortable.create(editable, {
|
||||
filter: '.js-remove',
|
||||
onFilter: function (evt) {
|
||||
var el = editableList.closest(evt.item); // get dragged item
|
||||
el && el.parentNode.removeChild(el);
|
||||
}
|
||||
});
|
||||
</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="container" style="margin: 100px 0;">
|
||||
<div style="margin-left: 30px">
|
||||
<div><div class="layer title title_xl">See also</div></div>
|
||||
<div id="rubaxa-repos" data-force="100" class="layer" style="margin-top: -8px; margin-left: 10px; width: 90%; background-color: #fff;">Loading…</div>
|
||||
<script src="//rubaxa.github.io/repos.js"></script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<script src="Sortable.js"></script>
|
||||
<script src="//rubaxa.github.io/Ply/Ply.min.js"></script>
|
||||
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
|
||||
<script src="ng-sortable.js"></script>
|
||||
|
||||
<script src="st/app.js"></script>
|
||||
|
||||
|
||||
|
||||
<!-- highlight.js -->
|
||||
<style>
|
||||
/* Tomorrow Theme */
|
||||
/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */
|
||||
/* Original theme - https://github.com/chriskempson/tomorrow-theme */
|
||||
/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */
|
||||
.tomorrow-comment, pre .comment, pre .title {
|
||||
color: #8e908c;
|
||||
}
|
||||
|
||||
.tomorrow-red, pre .variable, pre .attribute, pre .tag, pre .regexp, pre .ruby .constant, pre .xml .tag .title, pre .xml .pi, pre .xml .doctype, pre .html .doctype, pre .css .id, pre .css .class, pre .css .pseudo {
|
||||
color: #c82829;
|
||||
}
|
||||
|
||||
.tomorrow-orange, pre .number, pre .preprocessor, pre .built_in, pre .literal, pre .params, pre .constant {
|
||||
color: #f5871f;
|
||||
}
|
||||
|
||||
.tomorrow-yellow, pre .class, pre .ruby .class .title, pre .css .rules .attribute {
|
||||
color: #eab700;
|
||||
}
|
||||
|
||||
.tomorrow-green, pre .string, pre .value, pre .inheritance, pre .header, pre .ruby .symbol, pre .xml .cdata {
|
||||
color: #718c00;
|
||||
}
|
||||
|
||||
.tomorrow-aqua, pre .css .hexcolor {
|
||||
color: #3e999f;
|
||||
}
|
||||
|
||||
.tomorrow-blue, pre .function, pre .python .decorator, pre .python .title, pre .ruby .function .title, pre .ruby .title .keyword, pre .perl .sub, pre .javascript .title, pre .coffeescript .title {
|
||||
color: #4271ae;
|
||||
}
|
||||
|
||||
.tomorrow-purple, pre .keyword, pre .javascript .function {
|
||||
color: #8959a8;
|
||||
}
|
||||
|
||||
pre {
|
||||
border: 0;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
pre code {
|
||||
display: block;
|
||||
color: #4d4d4c;
|
||||
font-size: 15px;
|
||||
font-family: Menlo, Monaco, Consolas, monospace;
|
||||
line-height: 1.5;
|
||||
padding: 30px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="//yandex.st/highlightjs/7.5/highlight.min.js"></script>
|
||||
<script>hljs.initHighlightingOnLoad();</script>
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-16483888-3', 'rubaxa.github.io');
|
||||
ga('send', 'pageview');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
61
public/static/libs/Sortable/jquery.binding.js
Normal file
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* jQuery plugin for Sortable
|
||||
* @author RubaXa <trash@rubaxa.org>
|
||||
* @license MIT
|
||||
*/
|
||||
(function (factory) {
|
||||
"use strict";
|
||||
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(["jquery"], factory);
|
||||
}
|
||||
else {
|
||||
/* jshint sub:true */
|
||||
factory(jQuery);
|
||||
}
|
||||
})(function ($) {
|
||||
"use strict";
|
||||
|
||||
|
||||
/* CODE */
|
||||
|
||||
|
||||
/**
|
||||
* jQuery plugin for Sortable
|
||||
* @param {Object|String} options
|
||||
* @param {..*} [args]
|
||||
* @returns {jQuery|*}
|
||||
*/
|
||||
$.fn.sortable = function (options) {
|
||||
var retVal,
|
||||
args = arguments;
|
||||
|
||||
this.each(function () {
|
||||
var $el = $(this),
|
||||
sortable = $el.data('sortable');
|
||||
|
||||
if (!sortable && (options instanceof Object || !options)) {
|
||||
sortable = new Sortable(this, options);
|
||||
$el.data('sortable', sortable);
|
||||
}
|
||||
|
||||
if (sortable) {
|
||||
if (options === 'widget') {
|
||||
retVal = sortable;
|
||||
}
|
||||
else if (options === 'destroy') {
|
||||
sortable.destroy();
|
||||
$el.removeData('sortable');
|
||||
}
|
||||
else if (typeof sortable[options] === 'function') {
|
||||
retVal = sortable[options].apply(sortable, [].slice.call(args, 1));
|
||||
}
|
||||
else if (options in sortable.options) {
|
||||
retVal = sortable.option.apply(sortable, args);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return (retVal === void 0) ? this : retVal;
|
||||
};
|
||||
});
|
||||
44
public/static/libs/Sortable/package.json
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "sortablejs",
|
||||
"exportName": "Sortable",
|
||||
"version": "1.5.1",
|
||||
"devDependencies": {
|
||||
"grunt": "*",
|
||||
"grunt-version": "*",
|
||||
"grunt-contrib-jshint": "*",
|
||||
"grunt-contrib-uglify": "*"
|
||||
},
|
||||
"description": "Minimalist JavaScript library for reorderable drag-and-drop lists on modern browsers and touch devices. No jQuery. Supports AngularJS and any CSS library, e.g. Bootstrap.",
|
||||
"main": "Sortable.js",
|
||||
"scripts": {
|
||||
"test": "./node_modules/grunt/bin/grunt",
|
||||
"prepublish": "./node_modules/grunt/bin/grunt"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/rubaxa/Sortable.git"
|
||||
},
|
||||
"files": [
|
||||
"Sortable.js",
|
||||
"Sortable.min.js"
|
||||
],
|
||||
"keywords": [
|
||||
"sortable",
|
||||
"reorder",
|
||||
"drag",
|
||||
"meteor",
|
||||
"angular",
|
||||
"ng-sortable",
|
||||
"react",
|
||||
"mixin"
|
||||
],
|
||||
"author": "Konstantin Lebedev <ibnRubaXa@gmail.com>",
|
||||
"license": "MIT",
|
||||
"spm": {
|
||||
"main": "Sortable.js",
|
||||
"ignore": [
|
||||
"meteor",
|
||||
"st"
|
||||
]
|
||||
}
|
||||
}
|
||||
243
public/static/libs/Sortable/st/app.css
Normal file
@@ -0,0 +1,243 @@
|
||||
html {
|
||||
background-image: -webkit-linear-gradient(bottom, #F4E2C9 20%, #F4D7C9 100%);
|
||||
background-image: -ms-linear-gradient(bottom, #F4E2C9 20%, #F4D7C9 100%);
|
||||
background-image: linear-gradient(to bottom, #F4E2C9 20%, #F4D7C9 100%);
|
||||
}
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
color: #464637;
|
||||
min-height: 100%;
|
||||
font-size: 20px;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
|
||||
h1 {
|
||||
color: #FF3F00;
|
||||
font-size: 20px;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-weight: 300;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 80%;
|
||||
margin: auto;
|
||||
min-width: 1100px;
|
||||
max-width: 1300px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@media (min-width: 750px) and (max-width: 970px){
|
||||
.container {
|
||||
width: 100%;
|
||||
min-width: 750px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.sortable-ghost {
|
||||
opacity: .2;
|
||||
}
|
||||
|
||||
#foo .sortable-drag {
|
||||
background: #daf4ff;
|
||||
}
|
||||
|
||||
|
||||
img {
|
||||
border: 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
|
||||
.logo {
|
||||
top: 55px;
|
||||
left: 30px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
|
||||
.title {
|
||||
color: #fff;
|
||||
padding: 3px 10px;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
background-color: #FF7373;
|
||||
z-index: 1000;
|
||||
}
|
||||
.title_xl {
|
||||
padding: 3px 15px;
|
||||
font-size: 40px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.tile {
|
||||
width: 22%;
|
||||
min-width: 245px;
|
||||
color: #FF7270;
|
||||
padding: 10px 30px;
|
||||
text-align: center;
|
||||
margin-top: 15px;
|
||||
margin-left: 5px;
|
||||
margin-right: 30px;
|
||||
background-color: #fff;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
.tile__name {
|
||||
cursor: move;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #FF7373;
|
||||
}
|
||||
|
||||
.tile__list {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.tile__list:last-child {
|
||||
margin-right: 0;
|
||||
min-height: 80px;
|
||||
}
|
||||
|
||||
.tile__list img {
|
||||
cursor: move;
|
||||
margin: 10px;
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.block {
|
||||
opacity: 1;
|
||||
position: absolute;
|
||||
}
|
||||
.block__list {
|
||||
padding: 20px 0;
|
||||
max-width: 360px;
|
||||
margin-top: -8px;
|
||||
margin-left: 5px;
|
||||
background-color: #fff;
|
||||
}
|
||||
.block__list-title {
|
||||
margin: -20px 0 0;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
background: #5F9EDF;
|
||||
}
|
||||
.block__list li { cursor: move; }
|
||||
|
||||
.block__list_words li {
|
||||
background-color: #fff;
|
||||
padding: 10px 40px;
|
||||
}
|
||||
.block__list_words .sortable-ghost {
|
||||
opacity: 0.4;
|
||||
background-color: #F4E2C9;
|
||||
}
|
||||
|
||||
.block__list_words li:first-letter {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.block__list_tags {
|
||||
padding-left: 30px;
|
||||
}
|
||||
|
||||
.block__list_tags:after {
|
||||
clear: both;
|
||||
content: '';
|
||||
display: block;
|
||||
}
|
||||
.block__list_tags li {
|
||||
color: #fff;
|
||||
float: left;
|
||||
margin: 8px 20px 10px 0;
|
||||
padding: 5px 10px;
|
||||
min-width: 10px;
|
||||
background-color: #5F9EDF;
|
||||
text-align: center;
|
||||
}
|
||||
.block__list_tags li:first-child:first-letter {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#editable {}
|
||||
#editable li {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#editable i {
|
||||
-webkit-transition: opacity .2s;
|
||||
transition: opacity .2s;
|
||||
opacity: 0;
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
color: #c00;
|
||||
top: 10px;
|
||||
right: 40px;
|
||||
position: absolute;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
#editable li:hover i {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
|
||||
#filter {}
|
||||
#filter button {
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
border: none;
|
||||
outline: 0;
|
||||
opacity: .5;
|
||||
margin: 10px 0 0;
|
||||
transition: opacity .1s ease;
|
||||
cursor: pointer;
|
||||
background: #5F9EDF;
|
||||
padding: 10px 0;
|
||||
font-size: 20px;
|
||||
}
|
||||
#filter button:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#filter .block__list {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.drag-handle {
|
||||
margin-right: 10px;
|
||||
font: bold 20px Sans-Serif;
|
||||
color: #5F9EDF;
|
||||
display: inline-block;
|
||||
cursor: move;
|
||||
cursor: -webkit-grabbing; /* overrides 'move' */
|
||||
}
|
||||
|
||||
#todos input {
|
||||
padding: 5px;
|
||||
font-size: 14px;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#nested ul li {
|
||||
background-color: rgba(0,0,0,.05);
|
||||
}
|
||||
226
public/static/libs/Sortable/st/app.js
Normal file
@@ -0,0 +1,226 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var byId = function (id) { return document.getElementById(id); },
|
||||
|
||||
loadScripts = function (desc, callback) {
|
||||
var deps = [], key, idx = 0;
|
||||
|
||||
for (key in desc) {
|
||||
deps.push(key);
|
||||
}
|
||||
|
||||
(function _next() {
|
||||
var pid,
|
||||
name = deps[idx],
|
||||
script = document.createElement('script');
|
||||
|
||||
script.type = 'text/javascript';
|
||||
script.src = desc[deps[idx]];
|
||||
|
||||
pid = setInterval(function () {
|
||||
if (window[name]) {
|
||||
clearTimeout(pid);
|
||||
|
||||
deps[idx++] = window[name];
|
||||
|
||||
if (deps[idx]) {
|
||||
_next();
|
||||
} else {
|
||||
callback.apply(null, deps);
|
||||
}
|
||||
}
|
||||
}, 30);
|
||||
|
||||
document.getElementsByTagName('head')[0].appendChild(script);
|
||||
})()
|
||||
},
|
||||
|
||||
console = window.console;
|
||||
|
||||
|
||||
if (!console.log) {
|
||||
console.log = function () {
|
||||
alert([].join.apply(arguments, ' '));
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Sortable.create(byId('foo'), {
|
||||
group: "words",
|
||||
animation: 150,
|
||||
store: {
|
||||
get: function (sortable) {
|
||||
var order = localStorage.getItem(sortable.options.group);
|
||||
return order ? order.split('|') : [];
|
||||
},
|
||||
set: function (sortable) {
|
||||
var order = sortable.toArray();
|
||||
localStorage.setItem(sortable.options.group, order.join('|'));
|
||||
}
|
||||
},
|
||||
onAdd: function (evt){ console.log('onAdd.foo:', [evt.item, evt.from]); },
|
||||
onUpdate: function (evt){ console.log('onUpdate.foo:', [evt.item, evt.from]); },
|
||||
onRemove: function (evt){ console.log('onRemove.foo:', [evt.item, evt.from]); },
|
||||
onStart:function(evt){ console.log('onStart.foo:', [evt.item, evt.from]);},
|
||||
onSort:function(evt){ console.log('onStart.foo:', [evt.item, evt.from]);},
|
||||
onEnd: function(evt){ console.log('onEnd.foo:', [evt.item, evt.from]);}
|
||||
});
|
||||
|
||||
|
||||
Sortable.create(byId('bar'), {
|
||||
group: "words",
|
||||
animation: 150,
|
||||
onAdd: function (evt){ console.log('onAdd.bar:', evt.item); },
|
||||
onUpdate: function (evt){ console.log('onUpdate.bar:', evt.item); },
|
||||
onRemove: function (evt){ console.log('onRemove.bar:', evt.item); },
|
||||
onStart:function(evt){ console.log('onStart.foo:', evt.item);},
|
||||
onEnd: function(evt){ console.log('onEnd.foo:', evt.item);}
|
||||
});
|
||||
|
||||
|
||||
// Multi groups
|
||||
Sortable.create(byId('multi'), {
|
||||
animation: 150,
|
||||
draggable: '.tile',
|
||||
handle: '.tile__name'
|
||||
});
|
||||
|
||||
[].forEach.call(byId('multi').getElementsByClassName('tile__list'), function (el){
|
||||
Sortable.create(el, {
|
||||
group: 'photo',
|
||||
animation: 150
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Editable list
|
||||
var editableList = Sortable.create(byId('editable'), {
|
||||
animation: 150,
|
||||
filter: '.js-remove',
|
||||
onFilter: function (evt) {
|
||||
evt.item.parentNode.removeChild(evt.item);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
byId('addUser').onclick = function () {
|
||||
Ply.dialog('prompt', {
|
||||
title: 'Add',
|
||||
form: { name: 'name' }
|
||||
}).done(function (ui) {
|
||||
var el = document.createElement('li');
|
||||
el.innerHTML = ui.data.name + '<i class="js-remove">✖</i>';
|
||||
editableList.el.appendChild(el);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// Advanced groups
|
||||
[{
|
||||
name: 'advanced',
|
||||
pull: true,
|
||||
put: true
|
||||
},
|
||||
{
|
||||
name: 'advanced',
|
||||
pull: 'clone',
|
||||
put: false
|
||||
}, {
|
||||
name: 'advanced',
|
||||
pull: false,
|
||||
put: true
|
||||
}].forEach(function (groupOpts, i) {
|
||||
Sortable.create(byId('advanced-' + (i + 1)), {
|
||||
sort: (i != 1),
|
||||
group: groupOpts,
|
||||
animation: 150
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// 'handle' option
|
||||
Sortable.create(byId('handle-1'), {
|
||||
handle: '.drag-handle',
|
||||
animation: 150
|
||||
});
|
||||
|
||||
|
||||
// Angular example
|
||||
angular.module('todoApp', ['ng-sortable'])
|
||||
.constant('ngSortableConfig', {onEnd: function() {
|
||||
console.log('default onEnd()');
|
||||
}})
|
||||
.controller('TodoController', ['$scope', function ($scope) {
|
||||
$scope.todos = [
|
||||
{text: 'learn angular', done: true},
|
||||
{text: 'build an angular app', done: false}
|
||||
];
|
||||
|
||||
$scope.addTodo = function () {
|
||||
$scope.todos.push({text: $scope.todoText, done: false});
|
||||
$scope.todoText = '';
|
||||
};
|
||||
|
||||
$scope.remaining = function () {
|
||||
var count = 0;
|
||||
angular.forEach($scope.todos, function (todo) {
|
||||
count += todo.done ? 0 : 1;
|
||||
});
|
||||
return count;
|
||||
};
|
||||
|
||||
$scope.archive = function () {
|
||||
var oldTodos = $scope.todos;
|
||||
$scope.todos = [];
|
||||
angular.forEach(oldTodos, function (todo) {
|
||||
if (!todo.done) $scope.todos.push(todo);
|
||||
});
|
||||
};
|
||||
}])
|
||||
.controller('TodoControllerNext', ['$scope', function ($scope) {
|
||||
$scope.todos = [
|
||||
{text: 'learn Sortable', done: true},
|
||||
{text: 'use ng-sortable', done: false},
|
||||
{text: 'Enjoy', done: false}
|
||||
];
|
||||
|
||||
$scope.remaining = function () {
|
||||
var count = 0;
|
||||
angular.forEach($scope.todos, function (todo) {
|
||||
count += todo.done ? 0 : 1;
|
||||
});
|
||||
return count;
|
||||
};
|
||||
|
||||
$scope.sortableConfig = { group: 'todo', animation: 150 };
|
||||
'Start End Add Update Remove Sort'.split(' ').forEach(function (name) {
|
||||
$scope.sortableConfig['on' + name] = console.log.bind(console, name);
|
||||
});
|
||||
}]);
|
||||
})();
|
||||
|
||||
|
||||
|
||||
// Background
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
function setNoiseBackground(el, width, height, opacity) {
|
||||
var canvas = document.createElement("canvas");
|
||||
var context = canvas.getContext("2d");
|
||||
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
for (var i = 0; i < width; i++) {
|
||||
for (var j = 0; j < height; j++) {
|
||||
var val = Math.floor(Math.random() * 255);
|
||||
context.fillStyle = "rgba(" + val + "," + val + "," + val + "," + opacity + ")";
|
||||
context.fillRect(i, j, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
el.style.background = "url(" + canvas.toDataURL("image/png") + ")";
|
||||
}
|
||||
|
||||
setNoiseBackground(document.getElementsByTagName('body')[0], 50, 50, 0.02);
|
||||
}, false);
|
||||
BIN
public/static/libs/Sortable/st/face-01.jpg
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
public/static/libs/Sortable/st/face-02.jpg
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
public/static/libs/Sortable/st/face-03.jpg
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
public/static/libs/Sortable/st/face-04.jpg
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
public/static/libs/Sortable/st/face-05.jpg
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
public/static/libs/Sortable/st/face-06.jpg
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
public/static/libs/Sortable/st/face-07.jpg
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
public/static/libs/Sortable/st/face-08.jpg
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
public/static/libs/Sortable/st/face-09.jpg
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
32
public/static/libs/Sortable/st/iframe/frame.html
Normal file
@@ -0,0 +1,32 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- Latest compiled and minified CSS -->
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css"/>
|
||||
|
||||
|
||||
<!-- List with handle -->
|
||||
<div id="listWithHandle" class="list-group">
|
||||
<div class="list-group-item">
|
||||
<span class="badge">14</span>
|
||||
<span class="glyphicon glyphicon-move" aria-hidden="true"></span>
|
||||
Drag me by the handle
|
||||
</div>
|
||||
<div class="list-group-item">
|
||||
<span class="badge">2</span>
|
||||
<span class="glyphicon glyphicon-move" aria-hidden="true"></span>
|
||||
You can also select text
|
||||
</div>
|
||||
<div class="list-group-item">
|
||||
<span class="badge">1</span>
|
||||
<span class="glyphicon glyphicon-move" aria-hidden="true"></span>
|
||||
Best of both worlds!
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
49
public/static/libs/Sortable/st/iframe/index.html
Normal file
@@ -0,0 +1,49 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>IFrame playground</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
<!-- Latest compiled and minified CSS -->
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css"/>
|
||||
|
||||
|
||||
<!-- Latest Sortable -->
|
||||
<script src="../../Sortable.js"></script>
|
||||
|
||||
|
||||
<!-- Simple List -->
|
||||
<div id="simpleList" class="list-group">
|
||||
<div class="list-group-item">This is <a href="http://rubaxa.github.io/Sortable/">Sortable</a></div>
|
||||
<div class="list-group-item">It works with Bootstrap...</div>
|
||||
<div class="list-group-item">...out of the box.</div>
|
||||
<div class="list-group-item">It has support for touch devices.</div>
|
||||
<div class="list-group-item">Just drag some elements around.</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
Sortable.create(simpleList, {group: 'shared'});
|
||||
|
||||
|
||||
var iframe = document.createElement('iframe');
|
||||
|
||||
iframe.src = 'frame.html';
|
||||
iframe.width = '100%';
|
||||
iframe.onload = function () {
|
||||
var doc = iframe.contentDocument,
|
||||
list = doc.getElementById('listWithHandle');
|
||||
|
||||
Sortable.create(list, {group: 'shared'});
|
||||
};
|
||||
|
||||
|
||||
document.body.appendChild(iframe);
|
||||
})();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
BIN
public/static/libs/Sortable/st/logo.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
public/static/libs/Sortable/st/og-image.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
14
public/static/libs/art-template/.bower.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "art-template",
|
||||
"homepage": "https://github.com/aui/artTemplate",
|
||||
"version": "3.1.3",
|
||||
"_release": "3.1.3",
|
||||
"_resolution": {
|
||||
"type": "version",
|
||||
"tag": "v3.1.3",
|
||||
"commit": "b1085f546f6d3abbf74d10a5f69d24a63e932e86"
|
||||
},
|
||||
"_source": "https://github.com/aui/artTemplate.git",
|
||||
"_target": "^3.1.3",
|
||||
"_originalSource": "art-template"
|
||||
}
|
||||
4
public/static/libs/art-template/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
.vscode
|
||||
coverage
|
||||
3
public/static/libs/art-template/.npmignore
Normal file
@@ -0,0 +1,3 @@
|
||||
test
|
||||
demo
|
||||
doc
|
||||
99
public/static/libs/art-template/Gruntfile.js
Normal file
@@ -0,0 +1,99 @@
|
||||
module.exports = function (grunt) {
|
||||
|
||||
var sources_native = [
|
||||
'src/intro.js',
|
||||
'src/template.js',
|
||||
'src/config.js',
|
||||
'src/cache.js',
|
||||
'src/render.js',
|
||||
'src/renderFile.js',
|
||||
'src/get.js',
|
||||
'src/utils.js',
|
||||
'src/helper.js',
|
||||
'src/onerror.js',
|
||||
'src/compile.js',
|
||||
//<<<< 'src/syntax.js',
|
||||
'src/outro.js'
|
||||
];
|
||||
|
||||
var sources_simple = Array.apply(null, sources_native);
|
||||
sources_simple.splice(sources_native.length - 1, 0, 'src/syntax.js');
|
||||
|
||||
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
meta: {
|
||||
banner: '/*!<%= pkg.name %> - Template Engine | <%= pkg.homepage %>*/\n'
|
||||
},
|
||||
concat: {
|
||||
options: {
|
||||
separator: ''
|
||||
},
|
||||
|
||||
'native': {
|
||||
src: sources_native,
|
||||
dest: 'dist/template-native-debug.js'
|
||||
},
|
||||
|
||||
simple: {
|
||||
src: sources_simple,
|
||||
dest: 'dist/template-debug.js'
|
||||
}
|
||||
},
|
||||
uglify: {
|
||||
options: {
|
||||
banner: '<%= meta.banner %>'
|
||||
},
|
||||
'native': {
|
||||
src: '<%= concat.native.dest %>',
|
||||
dest: 'dist/template-native.js'
|
||||
},
|
||||
simple: {
|
||||
src: '<%= concat.simple.dest %>',
|
||||
dest: 'dist/template.js'
|
||||
}
|
||||
},
|
||||
qunit: {
|
||||
files: ['test/**/*.html']
|
||||
},
|
||||
jshint: {
|
||||
files: [
|
||||
'dist/template-native.js',
|
||||
'dist/template.js'
|
||||
],
|
||||
options: {
|
||||
curly: true,
|
||||
eqeqeq: true,
|
||||
immed: true,
|
||||
latedef: true,
|
||||
newcap: true,
|
||||
noarg: true,
|
||||
sub: true,
|
||||
undef: true,
|
||||
boss: true,
|
||||
eqnull: true,
|
||||
browser: true
|
||||
},
|
||||
globals: {
|
||||
console: true,
|
||||
define: true,
|
||||
global: true,
|
||||
module: true
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
files: '<config:lint.files>',
|
||||
tasks: 'lint qunit'
|
||||
}
|
||||
});
|
||||
|
||||
grunt.loadNpmTasks('grunt-contrib-uglify');
|
||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
||||
//grunt.loadNpmTasks('grunt-contrib-qunit');
|
||||
//grunt.loadNpmTasks('grunt-contrib-watch');
|
||||
grunt.loadNpmTasks('grunt-contrib-concat');
|
||||
|
||||
|
||||
grunt.registerTask('default', ['concat', /*'jshint',*/ 'uglify']);
|
||||
|
||||
};
|
||||
303
public/static/libs/art-template/README.md
Normal file
@@ -0,0 +1,303 @@
|
||||
# artTemplate-3.0
|
||||
|
||||
新一代 javascript 模板引擎
|
||||
|
||||
> 后会无期。2016-12-22
|
||||
|
||||
## 目录
|
||||
|
||||
* [特性](#特性)
|
||||
* [快速上手](#快速上手)
|
||||
* [模板语法](#模板语法)
|
||||
* [下载](#下载)
|
||||
* [方法](#方法)
|
||||
* [NodeJS](#nodejs)
|
||||
* [使用预编译](#使用预编译)
|
||||
* [更新日志](#更新日志)
|
||||
* [授权协议](#授权协议)
|
||||
|
||||
## 特性
|
||||
|
||||
1. 性能卓越,执行速度通常是 Mustache 与 tmpl 的 20 多倍([性能测试](http://aui.github.com/artTemplate/test/test-speed.html))
|
||||
2. 支持运行时调试,可精确定位异常模板所在语句([演示](http://aui.github.io/artTemplate/demo/debug.html))
|
||||
3. 对 NodeJS Express 友好支持
|
||||
4. 安全,默认对输出进行转义、在沙箱中运行编译后的代码(Node版本可以安全执行用户上传的模板)
|
||||
5. 支持``include``语句
|
||||
6. 可在浏览器端实现按路径加载模板([详情](#使用预编译))
|
||||
7. 支持预编译,可将模板转换成为非常精简的 js 文件
|
||||
8. 模板语句简洁,无需前缀引用数据,有简洁版本与原生语法版本可选
|
||||
9. 支持所有流行的浏览器
|
||||
|
||||
## 快速上手
|
||||
|
||||
### 编写模板
|
||||
|
||||
使用一个``type="text/html"``的``script``标签存放模板:
|
||||
|
||||
<script id="test" type="text/html">
|
||||
<h1>{{title}}</h1>
|
||||
<ul>
|
||||
{{each list as value i}}
|
||||
<li>索引 {{i + 1}} :{{value}}</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</script>
|
||||
|
||||
### 渲染模板
|
||||
|
||||
var data = {
|
||||
title: '标签',
|
||||
list: ['文艺', '博客', '摄影', '电影', '民谣', '旅行', '吉他']
|
||||
};
|
||||
var html = template('test', data);
|
||||
document.getElementById('content').innerHTML = html;
|
||||
|
||||
|
||||
[演示](http://aui.github.com/artTemplate/demo/basic.html)
|
||||
|
||||
## 模板语法
|
||||
|
||||
有两个版本的模板语法可以选择。
|
||||
|
||||
### 简洁语法
|
||||
|
||||
推荐使用,语法简单实用,利于读写。
|
||||
|
||||
{{if admin}}
|
||||
{{include 'admin_content'}}
|
||||
|
||||
{{each list}}
|
||||
<div>{{$index}}. {{$value.user}}</div>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
|
||||
[查看语法与演示](https://github.com/aui/artTemplate/wiki/syntax:simple)
|
||||
|
||||
### 原生语法
|
||||
|
||||
<%if (admin){%>
|
||||
<%include('admin_content')%>
|
||||
|
||||
<%for (var i=0;i<list.length;i++) {%>
|
||||
<div><%=i%>. <%=list[i].user%></div>
|
||||
<%}%>
|
||||
<%}%>
|
||||
|
||||
[查看语法与演示](https://github.com/aui/artTemplate/wiki/syntax:native)
|
||||
|
||||
## 下载
|
||||
|
||||
* [template.js](https://raw.github.com/aui/artTemplate/master/dist/template.js) *(简洁语法版, 2.7kb)*
|
||||
* [template-native.js](https://raw.github.com/aui/artTemplate/master/dist/template-native.js) *(原生语法版, 2.3kb)*
|
||||
|
||||
## 方法
|
||||
|
||||
### template(id, data)
|
||||
|
||||
根据 id 渲染模板。内部会根据``document.getElementById(id)``查找模板。
|
||||
|
||||
如果没有 data 参数,那么将返回一渲染函数。
|
||||
|
||||
### template.``compile``(source, options)
|
||||
|
||||
将返回一个渲染函数。[演示](http://aui.github.com/artTemplate/demo/compile.html)
|
||||
|
||||
### template.``render``(source, options)
|
||||
|
||||
将返回渲染结果。
|
||||
|
||||
### template.``helper``(name, callback)
|
||||
|
||||
添加辅助方法。
|
||||
|
||||
例如时间格式器:[演示](http://aui.github.com/artTemplate/demo/helper.html)
|
||||
|
||||
### template.``config``(name, value)
|
||||
|
||||
更改引擎的默认配置。
|
||||
|
||||
字段 | 类型 | 默认值| 说明
|
||||
------------ | ------------- | ------------ | ------------
|
||||
openTag | String | ``'{{'`` | 逻辑语法开始标签
|
||||
closeTag | String | ``"}}"`` | 逻辑语法结束标签
|
||||
escape | Boolean | ``true`` | 是否编码输出 HTML 字符
|
||||
cache | Boolean | ``true`` | 是否开启缓存(依赖 options 的 filename 字段)
|
||||
compress | Boolean | ``false`` | 是否压缩 HTML 多余空白字符
|
||||
|
||||
## 使用预编译
|
||||
|
||||
可突破浏览器限制,让前端模板拥有后端模板一样的同步“文件”加载能力:
|
||||
|
||||
一、**按文件与目录组织模板**
|
||||
|
||||
```
|
||||
template('tpl/home/main', data)
|
||||
```
|
||||
|
||||
二、**模板支持引入子模板**
|
||||
|
||||
|
||||
{{include '../public/header'}}
|
||||
|
||||
### 基于预编译:
|
||||
|
||||
* 可将模板转换成为非常精简的 js 文件(不依赖引擎)
|
||||
* 使用同步模板加载接口
|
||||
* 支持多种 js 模块输出:AMD、CMD、CommonJS
|
||||
* 支持作为 GruntJS 插件构建
|
||||
* 前端模板可共享给 NodeJS 执行
|
||||
* 自动压缩打包模板
|
||||
|
||||
预编译工具:[TmodJS](http://github.com/aui/tmodjs/)
|
||||
|
||||
## NodeJS
|
||||
|
||||
### 安装
|
||||
|
||||
npm install art-template
|
||||
|
||||
### 使用
|
||||
|
||||
var template = require('art-template');
|
||||
var data = {list: ["aui", "test"]};
|
||||
|
||||
var html = template(__dirname + '/index/main', data);
|
||||
|
||||
### 配置
|
||||
|
||||
NodeJS 版本新增了如下默认配置:
|
||||
|
||||
字段 | 类型 | 默认值| 说明
|
||||
------------ | ------------- | ------------ | ------------
|
||||
base | String | ``''`` | 指定模板目录
|
||||
extname | String | ``'.html'`` | 指定模板后缀名
|
||||
encoding | String | ``'utf-8'`` | 指定模板编码
|
||||
|
||||
配置``base``指定模板目录可以缩短模板的路径,并且能够避免``include``语句越级访问任意路径引发安全隐患,例如:
|
||||
|
||||
template.config('base', __dirname);
|
||||
var html = template('index/main', data)
|
||||
|
||||
### NodeJS + Express
|
||||
|
||||
var template = require('art-template');
|
||||
template.config('base', '');
|
||||
template.config('extname', '.html');
|
||||
app.engine('.html', template.__express);
|
||||
app.set('view engine', 'html');
|
||||
//app.set('views', __dirname + '/views');
|
||||
|
||||
运行 demo:
|
||||
|
||||
node demo/node-template-express.js
|
||||
|
||||
> 若使用 js 原生语法作为模板语法,请改用 ``require('art-template/node/template-native.js')``
|
||||
|
||||
## 升级参考
|
||||
|
||||
为了适配 NodeJS express,artTemplate v3.0.0 接口有调整。
|
||||
|
||||
### 接口变更
|
||||
|
||||
1. 默认使用简洁语法
|
||||
2. ``template.render()``方法的第一个参数不再是 id,而是模板字符串
|
||||
3. 使用新的配置接口``template.config()``并且字段名有修改
|
||||
4. ``template.compile()``方法不支持 id 参数
|
||||
5. helper 方法不再强制原文输出,是否编码取决于模板语句
|
||||
6. ``template.helpers`` 中的``$string``、``$escape``、``$each``已迁移到``template.utils``中
|
||||
7. ``template()``方法不支持传入模板直接编译
|
||||
|
||||
### 升级方法
|
||||
|
||||
1. 如果想继续使用 js 原生语法作为模板语言,请使用 [template-native.js](https://raw.github.com/aui/artTemplate/master/dist/template-native.js)
|
||||
2. 查找项目```template.render```替换为```template```
|
||||
3. 使用``template.config(name, value)``来替换以前的配置
|
||||
4. ``template()``方法直接传入的模板改用``template.compile()``(v2初期版本)
|
||||
|
||||
## 更新日志
|
||||
|
||||
### v3.1.0
|
||||
|
||||
1. 修复``template.runder()``方法与文档表现不一致的问题
|
||||
2. 去掉鸡肋的``fs.watch``特性
|
||||
|
||||
### v3.0.3
|
||||
|
||||
1. 解决``template.helper()``方法传入的数据被转成字符串的问题 #96
|
||||
2. 解决``{{value || value2}}``被识别为管道语句的问题 #105 <https://github.com/aui/tmodjs/issues/48>
|
||||
|
||||
### v3.0.2
|
||||
|
||||
1. ~~解决管道语法必须使用空格分隔的问题~~
|
||||
|
||||
### v3.0.1
|
||||
|
||||
1. 适配 express3.x 与 4.x,修复路径 BUG
|
||||
|
||||
### v3.0.0
|
||||
|
||||
1. 提供 NodeJS 专属版本,支持使用路径加载模板,并且模板的``include``语句也支持相对路径
|
||||
2. 适配 [express](http://expressjs.com) 框架
|
||||
3. 内置``print``语句支持传入多个参数
|
||||
4. 支持全局缓存配置
|
||||
5. 简洁语法版支持管道风格的 helper 调用,例如:``{{time | dateFormat:'yyyy年 MM月 dd日 hh:mm:ss'}}``
|
||||
|
||||
当前版本接口有调整,请阅读 [升级参考](#升级参考)
|
||||
|
||||
> artTemplate 预编译工具 [TmodJS](https://github.com/aui/tmodjs) 已更新
|
||||
|
||||
### v2.0.4
|
||||
|
||||
1. 修复低版本安卓浏览器编译后可能产生语法错误的问题(因为此版本浏览器 js 引擎存在 BUG)
|
||||
|
||||
### v2.0.3
|
||||
|
||||
1. 优化辅助方法性能
|
||||
2. NodeJS 用户可以通过 npm 获取 artTemplate:``$ npm install art-template -g``
|
||||
3. 不转义输出语句推荐使用``<%=#value%>``(兼容 v2.0.3 版本之前使用的``<%==value%>``),而简版语法则可以使用``{{#value}}``
|
||||
4. 提供简版语法的合并版本 dist/[template-simple.js](https://raw.github.com/aui/artTemplate/master/dist/template-simple.js)
|
||||
|
||||
### v2.0.2
|
||||
|
||||
1. 优化自定义语法扩展,减少体积
|
||||
2. [重要]为了最大化兼容第三方库,自定义语法扩展默认界定符修改为``{{``与``}}``。
|
||||
3. 修复合并工具的BUG [#25](https://github.com/aui/artTemplate/issues/25)
|
||||
4. 公开了内部缓存,可以通过``template.cache``访问到编译后的函数
|
||||
5. 公开了辅助方法缓存,可以通过``template.helpers``访问到
|
||||
6. 优化了调试信息
|
||||
|
||||
### v2.0.1
|
||||
|
||||
1. 修复模板变量静态分析的[BUG](https://github.com/aui/artTemplate/pull/22)
|
||||
|
||||
### v2.0 release
|
||||
|
||||
1. ~~编译工具更名为 atc,成为 artTemplate 的子项目单独维护:<https://github.com/cdc-im/atc>~~
|
||||
|
||||
### v2.0 beta5
|
||||
|
||||
1. 修复编译工具可能存在重复依赖的问题。感谢 @warmhug
|
||||
2. 修复预编译``include``内部实现可能产生上下文不一致的问题。感谢 @warmhug
|
||||
3. 编译工具支持使用拖拽文件进行单独编译
|
||||
|
||||
### v2.0 beta4
|
||||
|
||||
1. 修复编译工具在压缩模板可能导致 HTML 意外截断的问题。感谢 @warmhug
|
||||
2. 完善编译工具对``include``支持支持,可以支持不同目录之间模板嵌套
|
||||
3. 修复编译工具没能正确处理自定义语法插件的辅助方法
|
||||
|
||||
### v2.0 beta1
|
||||
|
||||
1. 对非 String、Number 类型的数据不输出,而 Function 类型求值后输出。
|
||||
2. 默认对 html 进行转义输出,原文输出可使用``<%==value%>``(备注:v2.0.3 推荐使用``<%=#value%>``),也可以关闭默认的转义功能``template.defaults.escape = false``。
|
||||
3. 增加批处理工具支持把模板编译成不依赖模板引擎的 js 文件,可通过 RequireJS、SeaJS 等模块加载器进行异步加载。
|
||||
|
||||
## 授权协议
|
||||
|
||||
Released under the MIT, BSD, and GPL Licenses
|
||||
|
||||
============
|
||||
|
||||
[所有演示例子](http://aui.github.com/artTemplate/demo/index.html) | [引擎原理](http://cdc.tencent.com/?p=5723)
|
||||
|
||||
© tencent.com
|
||||
34
public/static/libs/art-template/demo/basic.html
Normal file
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>basic-demo</title>
|
||||
<script src="../dist/template.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="content"></div>
|
||||
<script id="test" type="text/html">
|
||||
{{if isAdmin}}
|
||||
|
||||
<h1>{{title}}</h1>
|
||||
<ul>
|
||||
{{each list as value i}}
|
||||
<li>索引 {{i + 1}} :{{value}}</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
||||
{{/if}}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
var data = {
|
||||
title: '基本例子',
|
||||
isAdmin: true,
|
||||
list: ['文艺', '博客', '摄影', '电影', '民谣', '旅行', '吉他']
|
||||
};
|
||||
var html = template('test', data);
|
||||
document.getElementById('content').innerHTML = html;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
27
public/static/libs/art-template/demo/compile.html
Normal file
@@ -0,0 +1,27 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>compile-demo</title>
|
||||
<script src="../dist/template.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>在javascript中存放模板</h1>
|
||||
<div id="content"></div>
|
||||
<script>
|
||||
var source = '<ul>'
|
||||
+ '{{each list as value i}}'
|
||||
+ '<li>索引 {{i + 1}} :{{value}}</li>'
|
||||
+ '{{/each}}'
|
||||
+ '</ul>';
|
||||
|
||||
var render = template.compile(source);
|
||||
var html = render({
|
||||
list: ['摄影', '电影', '民谣', '旅行', '吉他']
|
||||
});
|
||||
|
||||
document.getElementById('content').innerHTML = html;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
24
public/static/libs/art-template/demo/debug-syntax.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>debug-demo</title>
|
||||
<script src="../dist/template.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>错误捕获(请打开控制台)</h1>
|
||||
<script id="test" type="text/html">
|
||||
{{2 a ba d}}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
var html = '';
|
||||
html = template('test', {});
|
||||
document.write(html);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
29
public/static/libs/art-template/demo/debug.html
Normal file
@@ -0,0 +1,29 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>debug-demo</title>
|
||||
<script src="../dist/template.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>错误捕获(请打开控制台)</h1>
|
||||
<script id="test" type="text/html">
|
||||
<ul>
|
||||
{{each list}}
|
||||
{{/each}}
|
||||
|
||||
{{window.alert=null}}
|
||||
</ul>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
var html = '';
|
||||
html = template('test', {});
|
||||
document.write(html);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
87
public/static/libs/art-template/demo/helper.html
Normal file
@@ -0,0 +1,87 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>helper-demo</title>
|
||||
<script src="../dist/template.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>辅助方法</h1>
|
||||
<div id="content"></div>
|
||||
<script id="test" type="text/html">
|
||||
{{time | dateFormat:'yyyy年 MM月 dd日 hh:mm:ss'}}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 对日期进行格式化,
|
||||
* @param date 要格式化的日期
|
||||
* @param format 进行格式化的模式字符串
|
||||
* 支持的模式字母有:
|
||||
* y:年,
|
||||
* M:年中的月份(1-12),
|
||||
* d:月份中的天(1-31),
|
||||
* h:小时(0-23),
|
||||
* m:分(0-59),
|
||||
* s:秒(0-59),
|
||||
* S:毫秒(0-999),
|
||||
* q:季度(1-4)
|
||||
* @return String
|
||||
* @author yanis.wang
|
||||
* @see http://yaniswang.com/frontend/2013/02/16/dateformat-performance/
|
||||
*/
|
||||
template.helper('dateFormat', function (date, format) {
|
||||
|
||||
if (typeof date === "string") {
|
||||
var mts = date.match(/(\/Date\((\d+)\)\/)/);
|
||||
if (mts && mts.length >= 3) {
|
||||
date = parseInt(mts[2]);
|
||||
}
|
||||
}
|
||||
date = new Date(date);
|
||||
if (!date || date.toUTCString() == "Invalid Date") {
|
||||
return "";
|
||||
}
|
||||
|
||||
var map = {
|
||||
"M": date.getMonth() + 1, //月份
|
||||
"d": date.getDate(), //日
|
||||
"h": date.getHours(), //小时
|
||||
"m": date.getMinutes(), //分
|
||||
"s": date.getSeconds(), //秒
|
||||
"q": Math.floor((date.getMonth() + 3) / 3), //季度
|
||||
"S": date.getMilliseconds() //毫秒
|
||||
};
|
||||
|
||||
|
||||
format = format.replace(/([yMdhmsqS])+/g, function(all, t){
|
||||
var v = map[t];
|
||||
if(v !== undefined){
|
||||
if(all.length > 1){
|
||||
v = '0' + v;
|
||||
v = v.substr(v.length-2);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
else if(t === 'y'){
|
||||
return (date.getFullYear() + '').substr(4 - all.length);
|
||||
}
|
||||
return all;
|
||||
});
|
||||
return format;
|
||||
});
|
||||
|
||||
// --------
|
||||
|
||||
var data = {
|
||||
time: 1408536771253,
|
||||
};
|
||||
var html = template('test', data);
|
||||
document.getElementById('content').innerHTML = html;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
32
public/static/libs/art-template/demo/include.html
Normal file
@@ -0,0 +1,32 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>include-demo</title>
|
||||
<script src="../dist/template.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="content"></div>
|
||||
<script id="test" type="text/html">
|
||||
<h1>{{title}}</h1>
|
||||
{{include 'list'}}
|
||||
</script>
|
||||
<script id="list" type="text/html">
|
||||
<ul>
|
||||
{{each list as value i}}
|
||||
<li>索引 {{i + 1}} :{{value}}</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
var data = {
|
||||
title: '嵌入子模板',
|
||||
list: ['文艺', '博客', '摄影', '电影', '民谣', '旅行', '吉他']
|
||||
};
|
||||
var html = template('test', data);
|
||||
document.getElementById('content').innerHTML = html;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
21
public/static/libs/art-template/demo/index.html
Normal file
@@ -0,0 +1,21 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>demo</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>演示</h1>
|
||||
<nav>简洁语法演示 | <a href="template-native/index.html">js 原生语法演示</a></nav>
|
||||
<ul>
|
||||
<li><a href="basic.html">基本例子</a></li>
|
||||
<li><a href="no-escape.html">不转义HTML</a></li>
|
||||
<li><a href="compile.html">在javascript中存放模板</a></li>
|
||||
<li><a href="include.html">嵌入子模板(include)</a></li>
|
||||
<li><a href="helper.html">访问外部公用函数(辅助方法)</a></li>
|
||||
<li><a href="debug.html">错误调试</a></li>
|
||||
<li><a href="print.html">print方法</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
25
public/static/libs/art-template/demo/no-escape.html
Normal file
@@ -0,0 +1,25 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>no escape-demo</title>
|
||||
<script src="../dist/template.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>不转义HTML</h1>
|
||||
<div id="content"></div>
|
||||
<script id="test" type="text/html">
|
||||
<p>不转义:{{#value}}</p>
|
||||
<p>默认转义: {{value}}</p>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
var data = {
|
||||
value: '<span style="color:#F00">hello world!</span>'
|
||||
};
|
||||
var html = template('test', data);
|
||||
document.getElementById('content').innerHTML = html;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,48 @@
|
||||
var express = require('express');
|
||||
var template = require('../node/template.js');
|
||||
|
||||
|
||||
var app = module.exports = express();
|
||||
|
||||
template.config('extname', '.html');
|
||||
app.engine('.html', template.__express);
|
||||
app.set('view engine', 'html');
|
||||
app.set('views', __dirname + '/node-template');
|
||||
|
||||
|
||||
var demoData = {
|
||||
title: '国内要闻',
|
||||
time: (new Date).toString(),
|
||||
list: [
|
||||
{
|
||||
title: '<油价>调整周期缩至10个工作日 无4%幅度限制',
|
||||
url: 'http://finance.qq.com/zt2013/2013yj/index.htm'
|
||||
},
|
||||
{
|
||||
title: '明起汽油价格每吨下调310元 单价回归7元时代',
|
||||
url: 'http://finance.qq.com/a/20130326/007060.htm'
|
||||
},
|
||||
{
|
||||
title: '广东副县长疑因抛弃情妇遭6女子围殴 纪检调查',
|
||||
url: 'http://news.qq.com/a/20130326/001254.htm'
|
||||
},
|
||||
{
|
||||
title: '湖南27岁副县长回应质疑:父亲已不是领导',
|
||||
url: 'http://news.qq.com/a/20130326/000959.htm'
|
||||
},
|
||||
{
|
||||
title: '朝军进入战斗工作状态 称随时准备导弹攻击美国',
|
||||
url: 'http://news.qq.com/a/20130326/001307.htm'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('./index', demoData);
|
||||
});
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
35
public/static/libs/art-template/demo/node-template.js
Normal file
@@ -0,0 +1,35 @@
|
||||
var template = require('../node/template.js');
|
||||
//console.log(template);
|
||||
template.config('base', __dirname);// 设置模板根目录,默认为引擎所在目录
|
||||
template.config('compress', true);// 压缩输出
|
||||
|
||||
var html = template('node-template/index', {
|
||||
title: '国内要闻',
|
||||
time: (new Date).toString(),
|
||||
list: [
|
||||
{
|
||||
title: '<油价>调整周期缩至10个工作日 无4%幅度限制',
|
||||
url: 'http://finance.qq.com/zt2013/2013yj/index.htm'
|
||||
},
|
||||
{
|
||||
title: '明起汽油价格每吨下调310元 单价回归7元时代',
|
||||
url: 'http://finance.qq.com/a/20130326/007060.htm'
|
||||
},
|
||||
{
|
||||
title: '广东副县长疑因抛弃情妇遭6女子围殴 纪检调查',
|
||||
url: 'http://news.qq.com/a/20130326/001254.htm'
|
||||
},
|
||||
{
|
||||
title: '湖南27岁副县长回应质疑:父亲已不是领导',
|
||||
url: 'http://news.qq.com/a/20130326/000959.htm'
|
||||
},
|
||||
{
|
||||
title: '朝军进入战斗工作状态 称随时准备导弹攻击美国',
|
||||
url: 'http://news.qq.com/a/20130326/001307.htm'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
|
||||
console.log(html);
|
||||
//console.log(template.cache)
|
||||
@@ -0,0 +1 @@
|
||||
(c) 2013
|
||||
@@ -0,0 +1,12 @@
|
||||
{{include './public/header'}}
|
||||
|
||||
<div id="main">
|
||||
<h3>{{title}}</h3>
|
||||
<ul>
|
||||
{{each list}}
|
||||
<li><a href="{{$value.url}}">{{$value.title}}</a></li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{{include './public/footer'}}
|
||||
@@ -0,0 +1,6 @@
|
||||
<div id="footer">
|
||||
{{if time}}
|
||||
<p class='time'>{{time}}</p>
|
||||
{{/if}}
|
||||
{{include '../copyright'}}
|
||||
</div>
|
||||
@@ -0,0 +1,11 @@
|
||||
<!-- 头部 开始 -->
|
||||
<div id="header">
|
||||
{{include './logo'}}
|
||||
<ul id="nav">
|
||||
<li><a href="http://www.qq.com">首页</a></li>
|
||||
<li><a href="http://news.qq.com/">新闻</a></li>
|
||||
<li><a href="http://pp.qq.com/">图片</a></li>
|
||||
<li><a href="http://mil.qq.com/">军事</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- 头部 结束 -->
|
||||
@@ -0,0 +1,7 @@
|
||||
<!-- logo start -->
|
||||
<h1 id="logo">
|
||||
<a href="http://www.qq.com">
|
||||
<img width='134' height='44' src="http://mat1.gtimg.com/www/images/qq2012/qqlogo_1x.png" alt="腾讯网" />
|
||||
</a>
|
||||
</h1>
|
||||
<!-- logo end -->
|
||||
29
public/static/libs/art-template/demo/print.html
Normal file
@@ -0,0 +1,29 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>print-demo</title>
|
||||
<script src="../dist/template.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>print</h1>
|
||||
<script id="test" type="text/html">
|
||||
{{print a b c}}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
var html = '';
|
||||
|
||||
|
||||
var data = {
|
||||
a: 'hello',
|
||||
b: '--world',
|
||||
c: '--!!!'
|
||||
};
|
||||
|
||||
html = template('test', data);
|
||||
document.write(html);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>basic-demo</title>
|
||||
<script src="../../dist/template-native.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="content"></div>
|
||||
<script id="test" type="text/html">
|
||||
<% if (isAdmin) { %>
|
||||
|
||||
<h1><%=title%></h1>
|
||||
<ul>
|
||||
<% for (var i = 0; i < list.length; i ++) { %>
|
||||
<li>索引 <%= i + 1 %> :<%= list[i] %></li>
|
||||
<% } %>
|
||||
</ul>
|
||||
|
||||
<% } %>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
var data = {
|
||||
title: '基本例子',
|
||||
isAdmin: true,
|
||||
list: ['文艺', '博客', '摄影', '电影', '民谣', '旅行', '吉他']
|
||||
};
|
||||
var html = template('test', data);
|
||||
document.getElementById('content').innerHTML = html;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,27 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>compile-demo</title>
|
||||
<script src="../../dist/template-native.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>在javascript中存放模板</h1>
|
||||
<div id="content"></div>
|
||||
<script>
|
||||
var source = '<ul>'
|
||||
+ '<% for (var i = 0; i < list.length; i ++) { %>'
|
||||
+ '<li>索引 <%= i + 1 %> :<%= list[i] %></li>'
|
||||
+ '<% } %>'
|
||||
+ '</ul>';
|
||||
|
||||
var render = template.compile(source);
|
||||
var html = render({
|
||||
list: ['摄影', '电影', '民谣', '旅行', '吉他']
|
||||
});
|
||||
|
||||
document.getElementById('content').innerHTML = html;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,35 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>debug-demo</title>
|
||||
<script src="../../dist/template-native.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>错误捕获(请打开控制台)</h1>
|
||||
<script id="test" type="text/html">
|
||||
<ul>
|
||||
<% for7777777 (var i = 0; i < list.length; i ++) { %>
|
||||
<% } %>
|
||||
|
||||
<% window.alert = function (e) {
|
||||
(new Image).src = 'http://g.cn/log?'+ e;
|
||||
alert(e);
|
||||
};
|
||||
var alert = window.alert;
|
||||
|
||||
%>
|
||||
</ul>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
var html = '';
|
||||
html = template('test', {});
|
||||
document.write(html);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>debug-demo</title>
|
||||
<script src="../../dist/template-native.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>错误捕获(请打开控制台)</h1>
|
||||
<script id="test" type="text/html">
|
||||
<ul>
|
||||
<% for (var i = 0; i < list.length; i ++) { %>
|
||||
<% } %>
|
||||
|
||||
<% window.alert = function (e) {
|
||||
(new Image).src = 'http://g.cn/log?'+ e;
|
||||
alert(e);
|
||||
};
|
||||
var alert = window.alert;
|
||||
|
||||
%>
|
||||
</ul>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
var html = '';
|
||||
html = template('test', {});
|
||||
document.write(html);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>helper-demo</title>
|
||||
<script src="../../dist/template-native.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>辅助方法</h1>
|
||||
<div id="content"></div>
|
||||
<script id="test" type="text/html">
|
||||
<%=dateFormat(time, 'yyyy<b>年</b> MM月 dd日 hh:mm:ss')%>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 对日期进行格式化,
|
||||
* @param date 要格式化的日期
|
||||
* @param format 进行格式化的模式字符串
|
||||
* 支持的模式字母有:
|
||||
* y:年,
|
||||
* M:年中的月份(1-12),
|
||||
* d:月份中的天(1-31),
|
||||
* h:小时(0-23),
|
||||
* m:分(0-59),
|
||||
* s:秒(0-59),
|
||||
* S:毫秒(0-999),
|
||||
* q:季度(1-4)
|
||||
* @return String
|
||||
* @author yanis.wang
|
||||
* @see http://yaniswang.com/frontend/2013/02/16/dateformat-performance/
|
||||
*/
|
||||
template.helper('dateFormat', function (date, format) {
|
||||
|
||||
date = new Date(date);
|
||||
|
||||
var map = {
|
||||
"M": date.getMonth() + 1, //月份
|
||||
"d": date.getDate(), //日
|
||||
"h": date.getHours(), //小时
|
||||
"m": date.getMinutes(), //分
|
||||
"s": date.getSeconds(), //秒
|
||||
"q": Math.floor((date.getMonth() + 3) / 3), //季度
|
||||
"S": date.getMilliseconds() //毫秒
|
||||
};
|
||||
format = format.replace(/([yMdhmsqS])+/g, function(all, t){
|
||||
var v = map[t];
|
||||
if(v !== undefined){
|
||||
if(all.length > 1){
|
||||
v = '0' + v;
|
||||
v = v.substr(v.length-2);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
else if(t === 'y'){
|
||||
return (date.getFullYear() + '').substr(4 - all.length);
|
||||
}
|
||||
return all;
|
||||
});
|
||||
return format;
|
||||
});
|
||||
|
||||
// --------
|
||||
|
||||
var data = {
|
||||
time: (new Date).toString(),
|
||||
};
|
||||
var html = template('test', data);
|
||||
document.getElementById('content').innerHTML = html;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>include-demo</title>
|
||||
<script src="../../dist/template-native.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="content"></div>
|
||||
<script id="test" type="text/html">
|
||||
<h1><%=title%></h1>
|
||||
<%include('list')%>
|
||||
</script>
|
||||
<script id="list" type="text/html">
|
||||
<ul>
|
||||
<% for (var i = 0; i < list.length; i ++) { %>
|
||||
<li>索引 <%= i + 1 %> :<%= list[i] %></li>
|
||||
<% } %>
|
||||
</ul>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
var data = {
|
||||
title: '嵌入子模板',
|
||||
list: ['文艺', '博客', '摄影', '电影', '民谣', '旅行', '吉他']
|
||||
};
|
||||
var html = template('test', data);
|
||||
document.getElementById('content').innerHTML = html;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,22 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>demo</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>演示</h1>
|
||||
<nav><a href="../index.html">简洁语法演示</a> | js 原生语法演示</nav>
|
||||
<ul>
|
||||
<li><a href="basic.html">基本例子</a></li>
|
||||
<li><a href="no-escape.html">不转义HTML</a></li>
|
||||
<li><a href="compile.html">在javascript中存放模板</a></li>
|
||||
<li><a href="include.html">嵌入子模板(include)</a></li>
|
||||
<li><a href="helper.html">访问外部公用函数(辅助方法)</a></li>
|
||||
<li><a href="debug.html">错误调试</a></li>
|
||||
<li><a href="print.html">print方法</a></li>
|
||||
<li><a href="tag.html">自定义界定符</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,25 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>no escape-demo</title>
|
||||
<script src="../../dist/template-native.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>不转义HTML</h1>
|
||||
<div id="content"></div>
|
||||
<script id="test" type="text/html">
|
||||
<p>不转义:<%=#value%></p>
|
||||
<p>默认转义: <%=value%></p>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
var data = {
|
||||
value: '<span style="color:#F00">hello world!</span>'
|
||||
};
|
||||
var html = template('test', data);
|
||||
document.getElementById('content').innerHTML = html;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,30 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>print-demo</title>
|
||||
<script src="../../dist/template-native.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>print</h1>
|
||||
<script id="test" type="text/html">
|
||||
<% print(a, b, c) %>
|
||||
|
||||
</script>
|
||||
|
||||
<script>
|
||||
var html = '';
|
||||
|
||||
|
||||
var data = {
|
||||
a: 'hello',
|
||||
b: '--world',
|
||||
c: '--!!!'
|
||||
};
|
||||
|
||||
html = template('test', data);
|
||||
document.write(html);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,42 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>tag-demo</title>
|
||||
<script src="../../dist/template-native.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>自定义界定符</h1>
|
||||
<script id="test" type="text/html">
|
||||
<!--[if (title) {]-->
|
||||
<h3><!--[= title]--></h3>
|
||||
<!--[} else {]-->
|
||||
<h3>无标题</h3>
|
||||
<!--[}]-->
|
||||
<ul>
|
||||
<!--[for (var i = 0; i < list.length; i ++) {]-->
|
||||
<li>索引 <!--[= i + 1 ]--> :<!--[= list[i]]--></li>
|
||||
<!--[}]-->
|
||||
</ul>
|
||||
|
||||
</script>
|
||||
|
||||
<script>
|
||||
template.defaults.openTag = '<!--[';
|
||||
template.defaults.closeTag = ']-->';
|
||||
|
||||
|
||||
var html = '';
|
||||
var data = {
|
||||
title: '我的标签',
|
||||
list: ['文艺', '博客', '摄影', '电影', '民谣', '旅行', '吉他']
|
||||
};
|
||||
|
||||
|
||||
html = template('test', data);
|
||||
document.write(html);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
739
public/static/libs/art-template/dist/template-debug.js
vendored
Normal file
@@ -0,0 +1,739 @@
|
||||
/*!
|
||||
* artTemplate - Template Engine
|
||||
* https://github.com/aui/artTemplate
|
||||
* Released under the MIT, BSD, and GPL Licenses
|
||||
*/
|
||||
|
||||
!(function () {
|
||||
|
||||
|
||||
/**
|
||||
* 模板引擎
|
||||
* @name template
|
||||
* @param {String} 模板名
|
||||
* @param {Object, String} 数据。如果为字符串则编译并缓存编译结果
|
||||
* @return {String, Function} 渲染好的HTML字符串或者渲染方法
|
||||
*/
|
||||
var template = function (filename, content) {
|
||||
return typeof content === 'string'
|
||||
? compile(content, {
|
||||
filename: filename
|
||||
})
|
||||
: renderFile(filename, content);
|
||||
};
|
||||
|
||||
|
||||
template.version = '3.0.0';
|
||||
|
||||
|
||||
/**
|
||||
* 设置全局配置
|
||||
* @name template.config
|
||||
* @param {String} 名称
|
||||
* @param {Any} 值
|
||||
*/
|
||||
template.config = function (name, value) {
|
||||
defaults[name] = value;
|
||||
};
|
||||
|
||||
|
||||
|
||||
var defaults = template.defaults = {
|
||||
openTag: '<%', // 逻辑语法开始标签
|
||||
closeTag: '%>', // 逻辑语法结束标签
|
||||
escape: true, // 是否编码输出变量的 HTML 字符
|
||||
cache: true, // 是否开启缓存(依赖 options 的 filename 字段)
|
||||
compress: false, // 是否压缩输出
|
||||
parser: null // 自定义语法格式器 @see: template-syntax.js
|
||||
};
|
||||
|
||||
|
||||
var cacheStore = template.cache = {};
|
||||
|
||||
|
||||
/**
|
||||
* 渲染模板
|
||||
* @name template.render
|
||||
* @param {String} 模板
|
||||
* @param {Object} 数据
|
||||
* @return {String} 渲染好的字符串
|
||||
*/
|
||||
template.render = function (source, options) {
|
||||
return compile(source)(options);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 渲染模板(根据模板名)
|
||||
* @name template.render
|
||||
* @param {String} 模板名
|
||||
* @param {Object} 数据
|
||||
* @return {String} 渲染好的字符串
|
||||
*/
|
||||
var renderFile = template.renderFile = function (filename, data) {
|
||||
var fn = template.get(filename) || showDebugInfo({
|
||||
filename: filename,
|
||||
name: 'Render Error',
|
||||
message: 'Template not found'
|
||||
});
|
||||
return data ? fn(data) : fn;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 获取编译缓存(可由外部重写此方法)
|
||||
* @param {String} 模板名
|
||||
* @param {Function} 编译好的函数
|
||||
*/
|
||||
template.get = function (filename) {
|
||||
|
||||
var cache;
|
||||
|
||||
if (cacheStore[filename]) {
|
||||
// 使用内存缓存
|
||||
cache = cacheStore[filename];
|
||||
} else if (typeof document === 'object') {
|
||||
// 加载模板并编译
|
||||
var elem = document.getElementById(filename);
|
||||
|
||||
if (elem) {
|
||||
var source = (elem.value || elem.innerHTML)
|
||||
.replace(/^\s*|\s*$/g, '');
|
||||
cache = compile(source, {
|
||||
filename: filename
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return cache;
|
||||
};
|
||||
|
||||
|
||||
var toString = function (value, type) {
|
||||
|
||||
if (typeof value !== 'string') {
|
||||
|
||||
type = typeof value;
|
||||
if (type === 'number') {
|
||||
value += '';
|
||||
} else if (type === 'function') {
|
||||
value = toString(value.call(value));
|
||||
} else {
|
||||
value = '';
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
|
||||
};
|
||||
|
||||
|
||||
var escapeMap = {
|
||||
"<": "<",
|
||||
">": ">",
|
||||
'"': """,
|
||||
"'": "'",
|
||||
"&": "&"
|
||||
};
|
||||
|
||||
|
||||
var escapeFn = function (s) {
|
||||
return escapeMap[s];
|
||||
};
|
||||
|
||||
var escapeHTML = function (content) {
|
||||
return toString(content)
|
||||
.replace(/&(?![\w#]+;)|[<>"']/g, escapeFn);
|
||||
};
|
||||
|
||||
|
||||
var isArray = Array.isArray || function (obj) {
|
||||
return ({}).toString.call(obj) === '[object Array]';
|
||||
};
|
||||
|
||||
|
||||
var each = function (data, callback) {
|
||||
var i, len;
|
||||
if (isArray(data)) {
|
||||
for (i = 0, len = data.length; i < len; i++) {
|
||||
callback.call(data, data[i], i, data);
|
||||
}
|
||||
} else {
|
||||
for (i in data) {
|
||||
callback.call(data, data[i], i);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var utils = template.utils = {
|
||||
|
||||
$helpers: {},
|
||||
|
||||
$include: renderFile,
|
||||
|
||||
$string: toString,
|
||||
|
||||
$escape: escapeHTML,
|
||||
|
||||
$each: each
|
||||
|
||||
};/**
|
||||
* 添加模板辅助方法
|
||||
* @name template.helper
|
||||
* @param {String} 名称
|
||||
* @param {Function} 方法
|
||||
*/
|
||||
template.helper = function (name, helper) {
|
||||
helpers[name] = helper;
|
||||
};
|
||||
|
||||
var helpers = template.helpers = utils.$helpers;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 模板错误事件(可由外部重写此方法)
|
||||
* @name template.onerror
|
||||
* @event
|
||||
*/
|
||||
template.onerror = function (e) {
|
||||
var message = 'Template Error\n\n';
|
||||
for (var name in e) {
|
||||
message += '<' + name + '>\n' + e[name] + '\n\n';
|
||||
}
|
||||
|
||||
if (typeof console === 'object') {
|
||||
console.error(message);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// 模板调试器
|
||||
var showDebugInfo = function (e) {
|
||||
|
||||
template.onerror(e);
|
||||
|
||||
return function () {
|
||||
return '{Template Error}';
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 编译模板
|
||||
* 2012-6-6 @TooBug: define 方法名改为 compile,与 Node Express 保持一致
|
||||
* @name template.compile
|
||||
* @param {String} 模板字符串
|
||||
* @param {Object} 编译选项
|
||||
*
|
||||
* - openTag {String}
|
||||
* - closeTag {String}
|
||||
* - filename {String}
|
||||
* - escape {Boolean}
|
||||
* - compress {Boolean}
|
||||
* - debug {Boolean}
|
||||
* - cache {Boolean}
|
||||
* - parser {Function}
|
||||
*
|
||||
* @return {Function} 渲染方法
|
||||
*/
|
||||
var compile = template.compile = function (source, options) {
|
||||
|
||||
// 合并默认配置
|
||||
options = options || {};
|
||||
for (var name in defaults) {
|
||||
if (options[name] === undefined) {
|
||||
options[name] = defaults[name];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var filename = options.filename;
|
||||
|
||||
|
||||
try {
|
||||
|
||||
var Render = compiler(source, options);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
e.filename = filename || 'anonymous';
|
||||
e.name = 'Syntax Error';
|
||||
|
||||
return showDebugInfo(e);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 对编译结果进行一次包装
|
||||
|
||||
function render (data) {
|
||||
|
||||
try {
|
||||
|
||||
return new Render(data, filename) + '';
|
||||
|
||||
} catch (e) {
|
||||
|
||||
// 运行时出错后自动开启调试模式重新编译
|
||||
if (!options.debug) {
|
||||
options.debug = true;
|
||||
return compile(source, options)(data);
|
||||
}
|
||||
|
||||
return showDebugInfo(e)();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
render.prototype = Render.prototype;
|
||||
render.toString = function () {
|
||||
return Render.toString();
|
||||
};
|
||||
|
||||
|
||||
if (filename && options.cache) {
|
||||
cacheStore[filename] = render;
|
||||
}
|
||||
|
||||
|
||||
return render;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// 数组迭代
|
||||
var forEach = utils.$each;
|
||||
|
||||
|
||||
// 静态分析模板变量
|
||||
var KEYWORDS =
|
||||
// 关键字
|
||||
'break,case,catch,continue,debugger,default,delete,do,else,false'
|
||||
+ ',finally,for,function,if,in,instanceof,new,null,return,switch,this'
|
||||
+ ',throw,true,try,typeof,var,void,while,with'
|
||||
|
||||
// 保留字
|
||||
+ ',abstract,boolean,byte,char,class,const,double,enum,export,extends'
|
||||
+ ',final,float,goto,implements,import,int,interface,long,native'
|
||||
+ ',package,private,protected,public,short,static,super,synchronized'
|
||||
+ ',throws,transient,volatile'
|
||||
|
||||
// ECMA 5 - use strict
|
||||
+ ',arguments,let,yield'
|
||||
|
||||
+ ',undefined';
|
||||
|
||||
var REMOVE_RE = /\/\*[\w\W]*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|"(?:[^"\\]|\\[\w\W])*"|'(?:[^'\\]|\\[\w\W])*'|\s*\.\s*[$\w\.]+/g;
|
||||
var SPLIT_RE = /[^\w$]+/g;
|
||||
var KEYWORDS_RE = new RegExp(["\\b" + KEYWORDS.replace(/,/g, '\\b|\\b') + "\\b"].join('|'), 'g');
|
||||
var NUMBER_RE = /^\d[^,]*|,\d[^,]*/g;
|
||||
var BOUNDARY_RE = /^,+|,+$/g;
|
||||
var SPLIT2_RE = /^$|,+/;
|
||||
|
||||
|
||||
// 获取变量
|
||||
function getVariable (code) {
|
||||
return code
|
||||
.replace(REMOVE_RE, '')
|
||||
.replace(SPLIT_RE, ',')
|
||||
.replace(KEYWORDS_RE, '')
|
||||
.replace(NUMBER_RE, '')
|
||||
.replace(BOUNDARY_RE, '')
|
||||
.split(SPLIT2_RE);
|
||||
};
|
||||
|
||||
|
||||
// 字符串转义
|
||||
function stringify (code) {
|
||||
return "'" + code
|
||||
// 单引号与反斜杠转义
|
||||
.replace(/('|\\)/g, '\\$1')
|
||||
// 换行符转义(windows + linux)
|
||||
.replace(/\r/g, '\\r')
|
||||
.replace(/\n/g, '\\n') + "'";
|
||||
}
|
||||
|
||||
|
||||
function compiler (source, options) {
|
||||
|
||||
var debug = options.debug;
|
||||
var openTag = options.openTag;
|
||||
var closeTag = options.closeTag;
|
||||
var parser = options.parser;
|
||||
var compress = options.compress;
|
||||
var escape = options.escape;
|
||||
|
||||
|
||||
|
||||
var line = 1;
|
||||
var uniq = {$data:1,$filename:1,$utils:1,$helpers:1,$out:1,$line:1};
|
||||
|
||||
|
||||
|
||||
var isNewEngine = ''.trim;// '__proto__' in {}
|
||||
var replaces = isNewEngine
|
||||
? ["$out='';", "$out+=", ";", "$out"]
|
||||
: ["$out=[];", "$out.push(", ");", "$out.join('')"];
|
||||
|
||||
var concat = isNewEngine
|
||||
? "$out+=text;return $out;"
|
||||
: "$out.push(text);";
|
||||
|
||||
var print = "function(){"
|
||||
+ "var text=''.concat.apply('',arguments);"
|
||||
+ concat
|
||||
+ "}";
|
||||
|
||||
var include = "function(filename,data){"
|
||||
+ "data=data||$data;"
|
||||
+ "var text=$utils.$include(filename,data,$filename);"
|
||||
+ concat
|
||||
+ "}";
|
||||
|
||||
var headerCode = "'use strict';"
|
||||
+ "var $utils=this,$helpers=$utils.$helpers,"
|
||||
+ (debug ? "$line=0," : "");
|
||||
|
||||
var mainCode = replaces[0];
|
||||
|
||||
var footerCode = "return new String(" + replaces[3] + ");"
|
||||
|
||||
// html与逻辑语法分离
|
||||
forEach(source.split(openTag), function (code) {
|
||||
code = code.split(closeTag);
|
||||
|
||||
var $0 = code[0];
|
||||
var $1 = code[1];
|
||||
|
||||
// code: [html]
|
||||
if (code.length === 1) {
|
||||
|
||||
mainCode += html($0);
|
||||
|
||||
// code: [logic, html]
|
||||
} else {
|
||||
|
||||
mainCode += logic($0);
|
||||
|
||||
if ($1) {
|
||||
mainCode += html($1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
var code = headerCode + mainCode + footerCode;
|
||||
|
||||
// 调试语句
|
||||
if (debug) {
|
||||
code = "try{" + code + "}catch(e){"
|
||||
+ "throw {"
|
||||
+ "filename:$filename,"
|
||||
+ "name:'Render Error',"
|
||||
+ "message:e.message,"
|
||||
+ "line:$line,"
|
||||
+ "source:" + stringify(source)
|
||||
+ ".split(/\\n/)[$line-1].replace(/^\\s+/,'')"
|
||||
+ "};"
|
||||
+ "}";
|
||||
}
|
||||
|
||||
|
||||
|
||||
try {
|
||||
|
||||
|
||||
var Render = new Function("$data", "$filename", code);
|
||||
Render.prototype = utils;
|
||||
|
||||
return Render;
|
||||
|
||||
} catch (e) {
|
||||
e.temp = "function anonymous($data,$filename) {" + code + "}";
|
||||
throw e;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 处理 HTML 语句
|
||||
function html (code) {
|
||||
|
||||
// 记录行号
|
||||
line += code.split(/\n/).length - 1;
|
||||
|
||||
// 压缩多余空白与注释
|
||||
if (compress) {
|
||||
code = code
|
||||
.replace(/\s+/g, ' ')
|
||||
.replace(/<!--[\w\W]*?-->/g, '');
|
||||
}
|
||||
|
||||
if (code) {
|
||||
code = replaces[1] + stringify(code) + replaces[2] + "\n";
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
// 处理逻辑语句
|
||||
function logic (code) {
|
||||
|
||||
var thisLine = line;
|
||||
|
||||
if (parser) {
|
||||
|
||||
// 语法转换插件钩子
|
||||
code = parser(code, options);
|
||||
|
||||
} else if (debug) {
|
||||
|
||||
// 记录行号
|
||||
code = code.replace(/\n/g, function () {
|
||||
line ++;
|
||||
return "$line=" + line + ";";
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 输出语句. 编码: <%=value%> 不编码:<%=#value%>
|
||||
// <%=#value%> 等同 v2.0.3 之前的 <%==value%>
|
||||
if (code.indexOf('=') === 0) {
|
||||
|
||||
var escapeSyntax = escape && !/^=[=#]/.test(code);
|
||||
|
||||
code = code.replace(/^=[=#]?|[\s;]*$/g, '');
|
||||
|
||||
// 对内容编码
|
||||
if (escapeSyntax) {
|
||||
|
||||
var name = code.replace(/\s*\([^\)]+\)/, '');
|
||||
|
||||
// 排除 utils.* | include | print
|
||||
|
||||
if (!utils[name] && !/^(include|print)$/.test(name)) {
|
||||
code = "$escape(" + code + ")";
|
||||
}
|
||||
|
||||
// 不编码
|
||||
} else {
|
||||
code = "$string(" + code + ")";
|
||||
}
|
||||
|
||||
|
||||
code = replaces[1] + code + replaces[2];
|
||||
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
code = "$line=" + thisLine + ";" + code;
|
||||
}
|
||||
|
||||
// 提取模板中的变量名
|
||||
forEach(getVariable(code), function (name) {
|
||||
|
||||
// name 值可能为空,在安卓低版本浏览器下
|
||||
if (!name || uniq[name]) {
|
||||
return;
|
||||
}
|
||||
|
||||
var value;
|
||||
|
||||
// 声明模板变量
|
||||
// 赋值优先级:
|
||||
// [include, print] > utils > helpers > data
|
||||
if (name === 'print') {
|
||||
|
||||
value = print;
|
||||
|
||||
} else if (name === 'include') {
|
||||
|
||||
value = include;
|
||||
|
||||
} else if (utils[name]) {
|
||||
|
||||
value = "$utils." + name;
|
||||
|
||||
} else if (helpers[name]) {
|
||||
|
||||
value = "$helpers." + name;
|
||||
|
||||
} else {
|
||||
|
||||
value = "$data." + name;
|
||||
}
|
||||
|
||||
headerCode += name + "=" + value + ",";
|
||||
uniq[name] = true;
|
||||
|
||||
|
||||
});
|
||||
|
||||
return code + "\n";
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
// 定义模板引擎的语法
|
||||
|
||||
|
||||
defaults.openTag = '{{';
|
||||
defaults.closeTag = '}}';
|
||||
|
||||
|
||||
var filtered = function (js, filter) {
|
||||
var parts = filter.split(':');
|
||||
var name = parts.shift();
|
||||
var args = parts.join(':') || '';
|
||||
|
||||
if (args) {
|
||||
args = ', ' + args;
|
||||
}
|
||||
|
||||
return '$helpers.' + name + '(' + js + args + ')';
|
||||
}
|
||||
|
||||
|
||||
defaults.parser = function (code, options) {
|
||||
|
||||
// var match = code.match(/([\w\$]*)(\b.*)/);
|
||||
// var key = match[1];
|
||||
// var args = match[2];
|
||||
// var split = args.split(' ');
|
||||
// split.shift();
|
||||
|
||||
code = code.replace(/^\s/, '');
|
||||
|
||||
var split = code.split(' ');
|
||||
var key = split.shift();
|
||||
var args = split.join(' ');
|
||||
|
||||
|
||||
|
||||
switch (key) {
|
||||
|
||||
case 'if':
|
||||
|
||||
code = 'if(' + args + '){';
|
||||
break;
|
||||
|
||||
case 'else':
|
||||
|
||||
if (split.shift() === 'if') {
|
||||
split = ' if(' + split.join(' ') + ')';
|
||||
} else {
|
||||
split = '';
|
||||
}
|
||||
|
||||
code = '}else' + split + '{';
|
||||
break;
|
||||
|
||||
case '/if':
|
||||
|
||||
code = '}';
|
||||
break;
|
||||
|
||||
case 'each':
|
||||
|
||||
var object = split[0] || '$data';
|
||||
var as = split[1] || 'as';
|
||||
var value = split[2] || '$value';
|
||||
var index = split[3] || '$index';
|
||||
|
||||
var param = value + ',' + index;
|
||||
|
||||
if (as !== 'as') {
|
||||
object = '[]';
|
||||
}
|
||||
|
||||
code = '$each(' + object + ',function(' + param + '){';
|
||||
break;
|
||||
|
||||
case '/each':
|
||||
|
||||
code = '});';
|
||||
break;
|
||||
|
||||
case 'echo':
|
||||
|
||||
code = 'print(' + args + ');';
|
||||
break;
|
||||
|
||||
case 'print':
|
||||
case 'include':
|
||||
|
||||
code = key + '(' + split.join(',') + ');';
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
// 过滤器(辅助方法)
|
||||
// {{value | filterA:'abcd' | filterB}}
|
||||
// >>> $helpers.filterB($helpers.filterA(value, 'abcd'))
|
||||
// TODO: {{ddd||aaa}} 不包含空格
|
||||
if (/^\s*\|\s*[\w\$]/.test(args)) {
|
||||
|
||||
var escape = true;
|
||||
|
||||
// {{#value | link}}
|
||||
if (code.indexOf('#') === 0) {
|
||||
code = code.substr(1);
|
||||
escape = false;
|
||||
}
|
||||
|
||||
var i = 0;
|
||||
var array = code.split('|');
|
||||
var len = array.length;
|
||||
var val = array[i++];
|
||||
|
||||
for (; i < len; i ++) {
|
||||
val = filtered(val, array[i]);
|
||||
}
|
||||
|
||||
code = (escape ? '=' : '=#') + val;
|
||||
|
||||
// 即将弃用 {{helperName value}}
|
||||
} else if (template.helpers[key]) {
|
||||
|
||||
code = '=#' + key + '(' + split.join(',') + ');';
|
||||
|
||||
// 内容直接输出 {{value}}
|
||||
} else {
|
||||
|
||||
code = '=' + code;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return code;
|
||||
};
|
||||
|
||||
|
||||
// CommonJs
|
||||
if (typeof exports === 'object' && typeof module !== 'undefined') {
|
||||
module.exports = template;
|
||||
// RequireJS && SeaJS
|
||||
} else if (typeof define === 'function') {
|
||||
define(function() {
|
||||
return template;
|
||||
});
|
||||
} else {
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
})();
|
||||
602
public/static/libs/art-template/dist/template-native-debug.js
vendored
Normal file
@@ -0,0 +1,602 @@
|
||||
/*!
|
||||
* artTemplate - Template Engine
|
||||
* https://github.com/aui/artTemplate
|
||||
* Released under the MIT, BSD, and GPL Licenses
|
||||
*/
|
||||
|
||||
!(function () {
|
||||
|
||||
|
||||
/**
|
||||
* 模板引擎
|
||||
* @name template
|
||||
* @param {String} 模板名
|
||||
* @param {Object, String} 数据。如果为字符串则编译并缓存编译结果
|
||||
* @return {String, Function} 渲染好的HTML字符串或者渲染方法
|
||||
*/
|
||||
var template = function (filename, content) {
|
||||
return typeof content === 'string'
|
||||
? compile(content, {
|
||||
filename: filename
|
||||
})
|
||||
: renderFile(filename, content);
|
||||
};
|
||||
|
||||
|
||||
template.version = '3.0.0';
|
||||
|
||||
|
||||
/**
|
||||
* 设置全局配置
|
||||
* @name template.config
|
||||
* @param {String} 名称
|
||||
* @param {Any} 值
|
||||
*/
|
||||
template.config = function (name, value) {
|
||||
defaults[name] = value;
|
||||
};
|
||||
|
||||
|
||||
|
||||
var defaults = template.defaults = {
|
||||
openTag: '<%', // 逻辑语法开始标签
|
||||
closeTag: '%>', // 逻辑语法结束标签
|
||||
escape: true, // 是否编码输出变量的 HTML 字符
|
||||
cache: true, // 是否开启缓存(依赖 options 的 filename 字段)
|
||||
compress: false, // 是否压缩输出
|
||||
parser: null // 自定义语法格式器 @see: template-syntax.js
|
||||
};
|
||||
|
||||
|
||||
var cacheStore = template.cache = {};
|
||||
|
||||
|
||||
/**
|
||||
* 渲染模板
|
||||
* @name template.render
|
||||
* @param {String} 模板
|
||||
* @param {Object} 数据
|
||||
* @return {String} 渲染好的字符串
|
||||
*/
|
||||
template.render = function (source, options) {
|
||||
return compile(source)(options);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 渲染模板(根据模板名)
|
||||
* @name template.render
|
||||
* @param {String} 模板名
|
||||
* @param {Object} 数据
|
||||
* @return {String} 渲染好的字符串
|
||||
*/
|
||||
var renderFile = template.renderFile = function (filename, data) {
|
||||
var fn = template.get(filename) || showDebugInfo({
|
||||
filename: filename,
|
||||
name: 'Render Error',
|
||||
message: 'Template not found'
|
||||
});
|
||||
return data ? fn(data) : fn;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 获取编译缓存(可由外部重写此方法)
|
||||
* @param {String} 模板名
|
||||
* @param {Function} 编译好的函数
|
||||
*/
|
||||
template.get = function (filename) {
|
||||
|
||||
var cache;
|
||||
|
||||
if (cacheStore[filename]) {
|
||||
// 使用内存缓存
|
||||
cache = cacheStore[filename];
|
||||
} else if (typeof document === 'object') {
|
||||
// 加载模板并编译
|
||||
var elem = document.getElementById(filename);
|
||||
|
||||
if (elem) {
|
||||
var source = (elem.value || elem.innerHTML)
|
||||
.replace(/^\s*|\s*$/g, '');
|
||||
cache = compile(source, {
|
||||
filename: filename
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return cache;
|
||||
};
|
||||
|
||||
|
||||
var toString = function (value, type) {
|
||||
|
||||
if (typeof value !== 'string') {
|
||||
|
||||
type = typeof value;
|
||||
if (type === 'number') {
|
||||
value += '';
|
||||
} else if (type === 'function') {
|
||||
value = toString(value.call(value));
|
||||
} else {
|
||||
value = '';
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
|
||||
};
|
||||
|
||||
|
||||
var escapeMap = {
|
||||
"<": "<",
|
||||
">": ">",
|
||||
'"': """,
|
||||
"'": "'",
|
||||
"&": "&"
|
||||
};
|
||||
|
||||
|
||||
var escapeFn = function (s) {
|
||||
return escapeMap[s];
|
||||
};
|
||||
|
||||
var escapeHTML = function (content) {
|
||||
return toString(content)
|
||||
.replace(/&(?![\w#]+;)|[<>"']/g, escapeFn);
|
||||
};
|
||||
|
||||
|
||||
var isArray = Array.isArray || function (obj) {
|
||||
return ({}).toString.call(obj) === '[object Array]';
|
||||
};
|
||||
|
||||
|
||||
var each = function (data, callback) {
|
||||
var i, len;
|
||||
if (isArray(data)) {
|
||||
for (i = 0, len = data.length; i < len; i++) {
|
||||
callback.call(data, data[i], i, data);
|
||||
}
|
||||
} else {
|
||||
for (i in data) {
|
||||
callback.call(data, data[i], i);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var utils = template.utils = {
|
||||
|
||||
$helpers: {},
|
||||
|
||||
$include: renderFile,
|
||||
|
||||
$string: toString,
|
||||
|
||||
$escape: escapeHTML,
|
||||
|
||||
$each: each
|
||||
|
||||
};/**
|
||||
* 添加模板辅助方法
|
||||
* @name template.helper
|
||||
* @param {String} 名称
|
||||
* @param {Function} 方法
|
||||
*/
|
||||
template.helper = function (name, helper) {
|
||||
helpers[name] = helper;
|
||||
};
|
||||
|
||||
var helpers = template.helpers = utils.$helpers;
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 模板错误事件(可由外部重写此方法)
|
||||
* @name template.onerror
|
||||
* @event
|
||||
*/
|
||||
template.onerror = function (e) {
|
||||
var message = 'Template Error\n\n';
|
||||
for (var name in e) {
|
||||
message += '<' + name + '>\n' + e[name] + '\n\n';
|
||||
}
|
||||
|
||||
if (typeof console === 'object') {
|
||||
console.error(message);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// 模板调试器
|
||||
var showDebugInfo = function (e) {
|
||||
|
||||
template.onerror(e);
|
||||
|
||||
return function () {
|
||||
return '{Template Error}';
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 编译模板
|
||||
* 2012-6-6 @TooBug: define 方法名改为 compile,与 Node Express 保持一致
|
||||
* @name template.compile
|
||||
* @param {String} 模板字符串
|
||||
* @param {Object} 编译选项
|
||||
*
|
||||
* - openTag {String}
|
||||
* - closeTag {String}
|
||||
* - filename {String}
|
||||
* - escape {Boolean}
|
||||
* - compress {Boolean}
|
||||
* - debug {Boolean}
|
||||
* - cache {Boolean}
|
||||
* - parser {Function}
|
||||
*
|
||||
* @return {Function} 渲染方法
|
||||
*/
|
||||
var compile = template.compile = function (source, options) {
|
||||
|
||||
// 合并默认配置
|
||||
options = options || {};
|
||||
for (var name in defaults) {
|
||||
if (options[name] === undefined) {
|
||||
options[name] = defaults[name];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var filename = options.filename;
|
||||
|
||||
|
||||
try {
|
||||
|
||||
var Render = compiler(source, options);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
e.filename = filename || 'anonymous';
|
||||
e.name = 'Syntax Error';
|
||||
|
||||
return showDebugInfo(e);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 对编译结果进行一次包装
|
||||
|
||||
function render (data) {
|
||||
|
||||
try {
|
||||
|
||||
return new Render(data, filename) + '';
|
||||
|
||||
} catch (e) {
|
||||
|
||||
// 运行时出错后自动开启调试模式重新编译
|
||||
if (!options.debug) {
|
||||
options.debug = true;
|
||||
return compile(source, options)(data);
|
||||
}
|
||||
|
||||
return showDebugInfo(e)();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
render.prototype = Render.prototype;
|
||||
render.toString = function () {
|
||||
return Render.toString();
|
||||
};
|
||||
|
||||
|
||||
if (filename && options.cache) {
|
||||
cacheStore[filename] = render;
|
||||
}
|
||||
|
||||
|
||||
return render;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// 数组迭代
|
||||
var forEach = utils.$each;
|
||||
|
||||
|
||||
// 静态分析模板变量
|
||||
var KEYWORDS =
|
||||
// 关键字
|
||||
'break,case,catch,continue,debugger,default,delete,do,else,false'
|
||||
+ ',finally,for,function,if,in,instanceof,new,null,return,switch,this'
|
||||
+ ',throw,true,try,typeof,var,void,while,with'
|
||||
|
||||
// 保留字
|
||||
+ ',abstract,boolean,byte,char,class,const,double,enum,export,extends'
|
||||
+ ',final,float,goto,implements,import,int,interface,long,native'
|
||||
+ ',package,private,protected,public,short,static,super,synchronized'
|
||||
+ ',throws,transient,volatile'
|
||||
|
||||
// ECMA 5 - use strict
|
||||
+ ',arguments,let,yield'
|
||||
|
||||
+ ',undefined';
|
||||
|
||||
var REMOVE_RE = /\/\*[\w\W]*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|"(?:[^"\\]|\\[\w\W])*"|'(?:[^'\\]|\\[\w\W])*'|\s*\.\s*[$\w\.]+/g;
|
||||
var SPLIT_RE = /[^\w$]+/g;
|
||||
var KEYWORDS_RE = new RegExp(["\\b" + KEYWORDS.replace(/,/g, '\\b|\\b') + "\\b"].join('|'), 'g');
|
||||
var NUMBER_RE = /^\d[^,]*|,\d[^,]*/g;
|
||||
var BOUNDARY_RE = /^,+|,+$/g;
|
||||
var SPLIT2_RE = /^$|,+/;
|
||||
|
||||
|
||||
// 获取变量
|
||||
function getVariable (code) {
|
||||
return code
|
||||
.replace(REMOVE_RE, '')
|
||||
.replace(SPLIT_RE, ',')
|
||||
.replace(KEYWORDS_RE, '')
|
||||
.replace(NUMBER_RE, '')
|
||||
.replace(BOUNDARY_RE, '')
|
||||
.split(SPLIT2_RE);
|
||||
};
|
||||
|
||||
|
||||
// 字符串转义
|
||||
function stringify (code) {
|
||||
return "'" + code
|
||||
// 单引号与反斜杠转义
|
||||
.replace(/('|\\)/g, '\\$1')
|
||||
// 换行符转义(windows + linux)
|
||||
.replace(/\r/g, '\\r')
|
||||
.replace(/\n/g, '\\n') + "'";
|
||||
}
|
||||
|
||||
|
||||
function compiler (source, options) {
|
||||
|
||||
var debug = options.debug;
|
||||
var openTag = options.openTag;
|
||||
var closeTag = options.closeTag;
|
||||
var parser = options.parser;
|
||||
var compress = options.compress;
|
||||
var escape = options.escape;
|
||||
|
||||
|
||||
|
||||
var line = 1;
|
||||
var uniq = {$data:1,$filename:1,$utils:1,$helpers:1,$out:1,$line:1};
|
||||
|
||||
|
||||
|
||||
var isNewEngine = ''.trim;// '__proto__' in {}
|
||||
var replaces = isNewEngine
|
||||
? ["$out='';", "$out+=", ";", "$out"]
|
||||
: ["$out=[];", "$out.push(", ");", "$out.join('')"];
|
||||
|
||||
var concat = isNewEngine
|
||||
? "$out+=text;return $out;"
|
||||
: "$out.push(text);";
|
||||
|
||||
var print = "function(){"
|
||||
+ "var text=''.concat.apply('',arguments);"
|
||||
+ concat
|
||||
+ "}";
|
||||
|
||||
var include = "function(filename,data){"
|
||||
+ "data=data||$data;"
|
||||
+ "var text=$utils.$include(filename,data,$filename);"
|
||||
+ concat
|
||||
+ "}";
|
||||
|
||||
var headerCode = "'use strict';"
|
||||
+ "var $utils=this,$helpers=$utils.$helpers,"
|
||||
+ (debug ? "$line=0," : "");
|
||||
|
||||
var mainCode = replaces[0];
|
||||
|
||||
var footerCode = "return new String(" + replaces[3] + ");"
|
||||
|
||||
// html与逻辑语法分离
|
||||
forEach(source.split(openTag), function (code) {
|
||||
code = code.split(closeTag);
|
||||
|
||||
var $0 = code[0];
|
||||
var $1 = code[1];
|
||||
|
||||
// code: [html]
|
||||
if (code.length === 1) {
|
||||
|
||||
mainCode += html($0);
|
||||
|
||||
// code: [logic, html]
|
||||
} else {
|
||||
|
||||
mainCode += logic($0);
|
||||
|
||||
if ($1) {
|
||||
mainCode += html($1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
var code = headerCode + mainCode + footerCode;
|
||||
|
||||
// 调试语句
|
||||
if (debug) {
|
||||
code = "try{" + code + "}catch(e){"
|
||||
+ "throw {"
|
||||
+ "filename:$filename,"
|
||||
+ "name:'Render Error',"
|
||||
+ "message:e.message,"
|
||||
+ "line:$line,"
|
||||
+ "source:" + stringify(source)
|
||||
+ ".split(/\\n/)[$line-1].replace(/^\\s+/,'')"
|
||||
+ "};"
|
||||
+ "}";
|
||||
}
|
||||
|
||||
|
||||
|
||||
try {
|
||||
|
||||
|
||||
var Render = new Function("$data", "$filename", code);
|
||||
Render.prototype = utils;
|
||||
|
||||
return Render;
|
||||
|
||||
} catch (e) {
|
||||
e.temp = "function anonymous($data,$filename) {" + code + "}";
|
||||
throw e;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 处理 HTML 语句
|
||||
function html (code) {
|
||||
|
||||
// 记录行号
|
||||
line += code.split(/\n/).length - 1;
|
||||
|
||||
// 压缩多余空白与注释
|
||||
if (compress) {
|
||||
code = code
|
||||
.replace(/\s+/g, ' ')
|
||||
.replace(/<!--[\w\W]*?-->/g, '');
|
||||
}
|
||||
|
||||
if (code) {
|
||||
code = replaces[1] + stringify(code) + replaces[2] + "\n";
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
// 处理逻辑语句
|
||||
function logic (code) {
|
||||
|
||||
var thisLine = line;
|
||||
|
||||
if (parser) {
|
||||
|
||||
// 语法转换插件钩子
|
||||
code = parser(code, options);
|
||||
|
||||
} else if (debug) {
|
||||
|
||||
// 记录行号
|
||||
code = code.replace(/\n/g, function () {
|
||||
line ++;
|
||||
return "$line=" + line + ";";
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 输出语句. 编码: <%=value%> 不编码:<%=#value%>
|
||||
// <%=#value%> 等同 v2.0.3 之前的 <%==value%>
|
||||
if (code.indexOf('=') === 0) {
|
||||
|
||||
var escapeSyntax = escape && !/^=[=#]/.test(code);
|
||||
|
||||
code = code.replace(/^=[=#]?|[\s;]*$/g, '');
|
||||
|
||||
// 对内容编码
|
||||
if (escapeSyntax) {
|
||||
|
||||
var name = code.replace(/\s*\([^\)]+\)/, '');
|
||||
|
||||
// 排除 utils.* | include | print
|
||||
|
||||
if (!utils[name] && !/^(include|print)$/.test(name)) {
|
||||
code = "$escape(" + code + ")";
|
||||
}
|
||||
|
||||
// 不编码
|
||||
} else {
|
||||
code = "$string(" + code + ")";
|
||||
}
|
||||
|
||||
|
||||
code = replaces[1] + code + replaces[2];
|
||||
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
code = "$line=" + thisLine + ";" + code;
|
||||
}
|
||||
|
||||
// 提取模板中的变量名
|
||||
forEach(getVariable(code), function (name) {
|
||||
|
||||
// name 值可能为空,在安卓低版本浏览器下
|
||||
if (!name || uniq[name]) {
|
||||
return;
|
||||
}
|
||||
|
||||
var value;
|
||||
|
||||
// 声明模板变量
|
||||
// 赋值优先级:
|
||||
// [include, print] > utils > helpers > data
|
||||
if (name === 'print') {
|
||||
|
||||
value = print;
|
||||
|
||||
} else if (name === 'include') {
|
||||
|
||||
value = include;
|
||||
|
||||
} else if (utils[name]) {
|
||||
|
||||
value = "$utils." + name;
|
||||
|
||||
} else if (helpers[name]) {
|
||||
|
||||
value = "$helpers." + name;
|
||||
|
||||
} else {
|
||||
|
||||
value = "$data." + name;
|
||||
}
|
||||
|
||||
headerCode += name + "=" + value + ",";
|
||||
uniq[name] = true;
|
||||
|
||||
|
||||
});
|
||||
|
||||
return code + "\n";
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
// CommonJs
|
||||
if (typeof exports === 'object' && typeof module !== 'undefined') {
|
||||
module.exports = template;
|
||||
// RequireJS && SeaJS
|
||||
} else if (typeof define === 'function') {
|
||||
define(function() {
|
||||
return template;
|
||||
});
|
||||
} else {
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
})();
|
||||
2
public/static/libs/art-template/dist/template-native.js
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/*!art-template - Template Engine | http://aui.github.com/artTemplate/*/
|
||||
!function(){function a(a){return a.replace(t,"").replace(u,",").replace(v,"").replace(w,"").replace(x,"").split(y)}function b(a){return"'"+a.replace(/('|\\)/g,"\\$1").replace(/\r/g,"\\r").replace(/\n/g,"\\n")+"'"}function c(c,d){function e(a){return m+=a.split(/\n/).length-1,k&&(a=a.replace(/\s+/g," ").replace(/<!--[\w\W]*?-->/g,"")),a&&(a=s[1]+b(a)+s[2]+"\n"),a}function f(b){var c=m;if(j?b=j(b,d):g&&(b=b.replace(/\n/g,function(){return m++,"$line="+m+";"})),0===b.indexOf("=")){var e=l&&!/^=[=#]/.test(b);if(b=b.replace(/^=[=#]?|[\s;]*$/g,""),e){var f=b.replace(/\s*\([^\)]+\)/,"");n[f]||/^(include|print)$/.test(f)||(b="$escape("+b+")")}else b="$string("+b+")";b=s[1]+b+s[2]}return g&&(b="$line="+c+";"+b),r(a(b),function(a){if(a&&!p[a]){var b;b="print"===a?u:"include"===a?v:n[a]?"$utils."+a:o[a]?"$helpers."+a:"$data."+a,w+=a+"="+b+",",p[a]=!0}}),b+"\n"}var g=d.debug,h=d.openTag,i=d.closeTag,j=d.parser,k=d.compress,l=d.escape,m=1,p={$data:1,$filename:1,$utils:1,$helpers:1,$out:1,$line:1},q="".trim,s=q?["$out='';","$out+=",";","$out"]:["$out=[];","$out.push(",");","$out.join('')"],t=q?"$out+=text;return $out;":"$out.push(text);",u="function(){var text=''.concat.apply('',arguments);"+t+"}",v="function(filename,data){data=data||$data;var text=$utils.$include(filename,data,$filename);"+t+"}",w="'use strict';var $utils=this,$helpers=$utils.$helpers,"+(g?"$line=0,":""),x=s[0],y="return new String("+s[3]+");";r(c.split(h),function(a){a=a.split(i);var b=a[0],c=a[1];1===a.length?x+=e(b):(x+=f(b),c&&(x+=e(c)))});var z=w+x+y;g&&(z="try{"+z+"}catch(e){throw {filename:$filename,name:'Render Error',message:e.message,line:$line,source:"+b(c)+".split(/\\n/)[$line-1].replace(/^\\s+/,'')};}");try{var A=new Function("$data","$filename",z);return A.prototype=n,A}catch(a){throw a.temp="function anonymous($data,$filename) {"+z+"}",a}}var d=function(a,b){return"string"==typeof b?q(b,{filename:a}):g(a,b)};d.version="3.0.0",d.config=function(a,b){e[a]=b};var e=d.defaults={openTag:"<%",closeTag:"%>",escape:!0,cache:!0,compress:!1,parser:null},f=d.cache={};d.render=function(a,b){return q(a)(b)};var g=d.renderFile=function(a,b){var c=d.get(a)||p({filename:a,name:"Render Error",message:"Template not found"});return b?c(b):c};d.get=function(a){var b;if(f[a])b=f[a];else if("object"==typeof document){var c=document.getElementById(a);if(c){var d=(c.value||c.innerHTML).replace(/^\s*|\s*$/g,"");b=q(d,{filename:a})}}return b};var h=function(a,b){return"string"!=typeof a&&(b=typeof a,"number"===b?a+="":a="function"===b?h(a.call(a)):""),a},i={"<":"<",">":">",'"':""","'":"'","&":"&"},j=function(a){return i[a]},k=function(a){return h(a).replace(/&(?![\w#]+;)|[<>"']/g,j)},l=Array.isArray||function(a){return"[object Array]"==={}.toString.call(a)},m=function(a,b){var c,d;if(l(a))for(c=0,d=a.length;c<d;c++)b.call(a,a[c],c,a);else for(c in a)b.call(a,a[c],c)},n=d.utils={$helpers:{},$include:g,$string:h,$escape:k,$each:m};d.helper=function(a,b){o[a]=b};var o=d.helpers=n.$helpers;d.onerror=function(a){var b="Template Error\n\n";for(var c in a)b+="<"+c+">\n"+a[c]+"\n\n";"object"==typeof console&&console.error(b)};var p=function(a){return d.onerror(a),function(){return"{Template Error}"}},q=d.compile=function(a,b){function d(c){try{return new i(c,h)+""}catch(d){return b.debug?p(d)():(b.debug=!0,q(a,b)(c))}}b=b||{};for(var g in e)void 0===b[g]&&(b[g]=e[g]);var h=b.filename;try{var i=c(a,b)}catch(a){return a.filename=h||"anonymous",a.name="Syntax Error",p(a)}return d.prototype=i.prototype,d.toString=function(){return i.toString()},h&&b.cache&&(f[h]=d),d},r=n.$each,s="break,case,catch,continue,debugger,default,delete,do,else,false,finally,for,function,if,in,instanceof,new,null,return,switch,this,throw,true,try,typeof,var,void,while,with,abstract,boolean,byte,char,class,const,double,enum,export,extends,final,float,goto,implements,import,int,interface,long,native,package,private,protected,public,short,static,super,synchronized,throws,transient,volatile,arguments,let,yield,undefined",t=/\/\*[\w\W]*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|"(?:[^"\\]|\\[\w\W])*"|'(?:[^'\\]|\\[\w\W])*'|\s*\.\s*[$\w\.]+/g,u=/[^\w$]+/g,v=new RegExp(["\\b"+s.replace(/,/g,"\\b|\\b")+"\\b"].join("|"),"g"),w=/^\d[^,]*|,\d[^,]*/g,x=/^,+|,+$/g,y=/^$|,+/;"object"==typeof exports&&"undefined"!=typeof module?module.exports=d:"function"==typeof define?define(function(){return d}):this.template=d}();
|
||||
2
public/static/libs/art-template/dist/template.js
vendored
Normal file
73
public/static/libs/art-template/doc/syntax-native.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# artTemplate 原生 js 模板语法版
|
||||
|
||||
## 使用
|
||||
|
||||
在页面中引用模板引擎:
|
||||
|
||||
<script src="dist/template-native.js"></script>
|
||||
|
||||
[下载](https://raw.github.com/aui/artTemplate/master/dist/template-native.js)
|
||||
|
||||
## 表达式
|
||||
|
||||
``<%`` 与 ``%>`` 符号包裹起来的语句则为模板的逻辑表达式。
|
||||
|
||||
### 输出表达式
|
||||
|
||||
对内容编码输出:
|
||||
|
||||
<%=content%>
|
||||
|
||||
不编码输出:
|
||||
|
||||
<%=#content%>
|
||||
|
||||
编码可以防止数据中含有 HTML 字符串,避免引起 XSS 攻击。
|
||||
|
||||
### 逻辑
|
||||
|
||||
支持使用 js 原生语法
|
||||
|
||||
<h1><%=title%></h1>
|
||||
<ul>
|
||||
<%for(i = 0; i < list.length; i ++) {%>
|
||||
<li>条目内容 <%=i + 1%> :<%=list[i]%></li>
|
||||
<%}%>
|
||||
</ul>
|
||||
|
||||
> 模板不能访问全局对象,公用的方法请参见文档[辅助方法](#辅助方法)章节
|
||||
|
||||
### 模板包含表达式
|
||||
|
||||
用于嵌入子模板。
|
||||
|
||||
<% include('template_name') %>
|
||||
|
||||
子模板默认共享当前数据,亦可以指定数据:
|
||||
|
||||
<% include('template_name', news_list) %>
|
||||
|
||||
## 辅助方法
|
||||
|
||||
使用``template.helper(name, callback)``注册公用辅助方法:
|
||||
|
||||
template.helper('dateFormat', function (date, format) {
|
||||
// ..
|
||||
return value;
|
||||
});
|
||||
|
||||
模板中使用的方式:
|
||||
|
||||
<%=dateFormat(content) %>
|
||||
|
||||
## 演示例子
|
||||
|
||||
* [基本例子](http://aui.github.io/artTemplate/demo/template-native/basic.html)
|
||||
* [不转义HTML](http://aui.github.io/artTemplate/demo/template-native/no-escape.html)
|
||||
* [在javascript中存放模板](http://aui.github.io/artTemplate/demo/template-native/compile.html)
|
||||
* [嵌入子模板(include)](http://aui.github.io/artTemplate/demo/template-native/include.html)
|
||||
* [访问外部公用函数(辅助方法)](http://aui.github.io/artTemplate/demo/template-native/helper.html)
|
||||
|
||||
----------------------------------------------
|
||||
|
||||
本文档针对 artTemplate v3.0.0 编写
|
||||
90
public/static/libs/art-template/doc/syntax-simple.md
Normal file
@@ -0,0 +1,90 @@
|
||||
# artTemplate 简洁语法版
|
||||
|
||||
## 使用
|
||||
|
||||
引用简洁语法的引擎版本,例如:
|
||||
|
||||
<script src="dist/template.js"></script>
|
||||
|
||||
[下载](https://raw.github.com/aui/artTemplate/master/dist/template.js)
|
||||
|
||||
## 表达式
|
||||
|
||||
``{{`` 与 ``}}`` 符号包裹起来的语句则为模板的逻辑表达式。
|
||||
|
||||
### 输出表达式
|
||||
|
||||
对内容编码输出:
|
||||
|
||||
{{content}}
|
||||
|
||||
不编码输出:
|
||||
|
||||
{{#content}}
|
||||
|
||||
编码可以防止数据中含有 HTML 字符串,避免引起 XSS 攻击。
|
||||
|
||||
### 条件表达式
|
||||
|
||||
{{if admin}}
|
||||
<p>admin</p>
|
||||
{{else if code > 0}}
|
||||
<p>master</p>
|
||||
{{else}}
|
||||
<p>error!</p>
|
||||
{{/if}}
|
||||
|
||||
### 遍历表达式
|
||||
|
||||
无论数组或者对象都可以用 each 进行遍历。
|
||||
|
||||
{{each list as value index}}
|
||||
<li>{{index}} - {{value.user}}</li>
|
||||
{{/each}}
|
||||
|
||||
亦可以被简写:
|
||||
|
||||
{{each list}}
|
||||
<li>{{$index}} - {{$value.user}}</li>
|
||||
{{/each}}
|
||||
|
||||
### 模板包含表达式
|
||||
|
||||
用于嵌入子模板。
|
||||
|
||||
{{include 'template_name'}}
|
||||
|
||||
子模板默认共享当前数据,亦可以指定数据:
|
||||
|
||||
{{include 'template_name' news_list}}
|
||||
|
||||
## 辅助方法
|
||||
|
||||
使用``template.helper(name, callback)``注册公用辅助方法:
|
||||
|
||||
```
|
||||
template.helper('dateFormat', function (date, format) {
|
||||
// ..
|
||||
return value;
|
||||
});
|
||||
```
|
||||
|
||||
模板中使用的方式:
|
||||
|
||||
{{time | dateFormat:'yyyy-MM-dd hh:mm:ss'}}
|
||||
|
||||
支持传入参数与嵌套使用:
|
||||
|
||||
{{time | say:'cd' | ubb | link}}
|
||||
|
||||
## 演示例子
|
||||
|
||||
* [基本例子](http://aui.github.io/artTemplate/demo/basic.html)
|
||||
* [不转义HTML](http://aui.github.io/artTemplate/demo/no-escape.html)
|
||||
* [在javascript中存放模板](http://aui.github.io/artTemplate/demo/compile.html)
|
||||
* [嵌入子模板(include)](http://aui.github.io/artTemplate/demo/include.html)
|
||||
* [访问外部公用函数(辅助方法)](http://aui.github.io/artTemplate/demo/helper.html)
|
||||
|
||||
----------------------------------------------
|
||||
|
||||
本文档针对 artTemplate v3.0.0+ 编写
|
||||
18
public/static/libs/art-template/loader/index.js
Normal file
@@ -0,0 +1,18 @@
|
||||
var template = require('art-template/dist/template');
|
||||
|
||||
module.exports = function(source) {
|
||||
this.cacheable && this.cacheable()
|
||||
|
||||
var ANONYMOUS_RE = /^function\s+anonymous/
|
||||
|
||||
template.onerror = function(e) {
|
||||
var message = 'Template Error\n\n';
|
||||
for (var name in e) {
|
||||
message += '<' + name + '>\n' + e[name] + '\n\n';
|
||||
}
|
||||
throw new SyntaxError(message)
|
||||
}
|
||||
|
||||
var render = template.compile(source, {}).toString().replace(ANONYMOUS_RE, 'function');
|
||||
return 'module.exports = require("art-template/loader/runtime")(' + render + ');';
|
||||
}
|
||||
14
public/static/libs/art-template/loader/package.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "t-loader",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"art-template": "^3.1.3"
|
||||
}
|
||||
}
|
||||
129
public/static/libs/art-template/loader/runtime.js
Normal file
@@ -0,0 +1,129 @@
|
||||
function template(content) {
|
||||
return compile(content);
|
||||
};
|
||||
|
||||
var String = this.String;
|
||||
|
||||
function toString(value, type) {
|
||||
|
||||
if (typeof value !== 'string') {
|
||||
|
||||
type = typeof value;
|
||||
if (type === 'number') {
|
||||
value += '';
|
||||
} else if (type === 'function') {
|
||||
value = toString(value.call(value));
|
||||
} else {
|
||||
value = '';
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
|
||||
};
|
||||
|
||||
|
||||
var escapeMap = {
|
||||
"<": "<",
|
||||
">": ">",
|
||||
'"': """,
|
||||
"'": "'",
|
||||
"&": "&"
|
||||
};
|
||||
|
||||
|
||||
function escapeFn(s) {
|
||||
return escapeMap[s];
|
||||
}
|
||||
|
||||
|
||||
function escapeHTML(content) {
|
||||
return toString(content)
|
||||
.replace(/&(?![\w#]+;)|[<>"']/g, escapeFn);
|
||||
};
|
||||
|
||||
|
||||
var isArray = Array.isArray || function (obj) {
|
||||
return ({}).toString.call(obj) === '[object Array]';
|
||||
};
|
||||
|
||||
|
||||
function each(data, callback) {
|
||||
if (isArray(data)) {
|
||||
for (var i = 0, len = data.length; i < len; i++) {
|
||||
callback.call(data, data[i], i, data);
|
||||
}
|
||||
} else {
|
||||
for (i in data) {
|
||||
callback.call(data, data[i], i);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var utils = template.utils = {
|
||||
|
||||
$helpers: {},
|
||||
|
||||
$include: function () {
|
||||
throw new Error('art-template/loader: not support `include`.');
|
||||
},
|
||||
|
||||
$string: toString,
|
||||
|
||||
$escape: escapeHTML,
|
||||
|
||||
$each: each
|
||||
|
||||
};
|
||||
|
||||
|
||||
var helpers = template.helpers = utils.$helpers;
|
||||
|
||||
|
||||
function compile(fn) {
|
||||
var render = function (data) {
|
||||
try {
|
||||
return new fn(data) + '';
|
||||
} catch (e) {
|
||||
return showDebugInfo(e)();
|
||||
}
|
||||
};
|
||||
|
||||
render.prototype = fn.prototype = utils;
|
||||
render.toString = function () {
|
||||
return fn + '';
|
||||
};
|
||||
|
||||
return render;
|
||||
};
|
||||
|
||||
|
||||
function showDebugInfo(e) {
|
||||
|
||||
var type = "{Template Error}";
|
||||
var message = e.stack || '';
|
||||
|
||||
if (message) {
|
||||
// 利用报错堆栈信息
|
||||
message = message.split('\n').slice(0, 2).join('\n');
|
||||
} else {
|
||||
// 调试版本,直接给出模板语句行
|
||||
for (var name in e) {
|
||||
message += "<" + name + ">\n" + e[name] + "\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
return function () {
|
||||
if (typeof console === "object") {
|
||||
console.error(type + "\n\n" + message);
|
||||
}
|
||||
return type;
|
||||
};
|
||||
};
|
||||
|
||||
template.helper = function (name, helper) {
|
||||
helpers[name] = helper;
|
||||
};
|
||||
|
||||
module.exports = template;
|
||||
90
public/static/libs/art-template/node/_node.js
Normal file
@@ -0,0 +1,90 @@
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
module.exports = function (template) {
|
||||
|
||||
var cacheStore = template.cache;
|
||||
var defaults = template.defaults;
|
||||
var rExtname;
|
||||
|
||||
// 提供新的配置字段
|
||||
defaults.base = '';
|
||||
defaults.extname = '.html';
|
||||
defaults.encoding = 'utf-8';
|
||||
|
||||
function compileFromFS(filename) {
|
||||
// 加载模板并编译
|
||||
var source = readTemplate(filename);
|
||||
|
||||
if (typeof source === 'string') {
|
||||
return template.compile(source, {
|
||||
filename: filename
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 重写引擎编译结果获取方法
|
||||
template.get = function (filename) {
|
||||
|
||||
var fn;
|
||||
|
||||
|
||||
if (cacheStore.hasOwnProperty(filename)) {
|
||||
// 使用内存缓存
|
||||
fn = cacheStore[filename];
|
||||
} else {
|
||||
fn = compileFromFS(filename);
|
||||
}
|
||||
|
||||
return fn;
|
||||
};
|
||||
|
||||
|
||||
function readTemplate (id) {
|
||||
id = path.join(defaults.base, id + defaults.extname);
|
||||
|
||||
if (id.indexOf(defaults.base) !== 0) {
|
||||
// 安全限制:禁止超出模板目录之外调用文件
|
||||
throw new Error('"' + id + '" is not in the template directory');
|
||||
} else {
|
||||
try {
|
||||
return fs.readFileSync(id, defaults.encoding);
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 重写模板`include``语句实现方法,转换模板为绝对路径
|
||||
template.utils.$include = function (filename, data, from) {
|
||||
|
||||
from = path.dirname(from);
|
||||
filename = path.join(from, filename);
|
||||
|
||||
return template.renderFile(filename, data);
|
||||
}
|
||||
|
||||
|
||||
// express support
|
||||
template.__express = function (file, options, fn) {
|
||||
|
||||
if (typeof options === 'function') {
|
||||
fn = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
|
||||
if (!rExtname) {
|
||||
// 去掉 express 传入的路径
|
||||
rExtname = new RegExp((defaults.extname + '$').replace(/\./g, '\\.'));
|
||||
}
|
||||
|
||||
|
||||
file = file.replace(rExtname, '');
|
||||
|
||||
options.filename = file;
|
||||
fn(null, template.renderFile(file, options));
|
||||
};
|
||||
|
||||
|
||||
return template;
|
||||
}
|
||||
9
public/static/libs/art-template/node/template-native.js
Normal file
@@ -0,0 +1,9 @@
|
||||
/*!
|
||||
* artTemplate[NodeJS]
|
||||
* https://github.com/aui/artTemplate
|
||||
* Released under the MIT, BSD, and GPL Licenses
|
||||
*/
|
||||
|
||||
var node = require('./_node.js');
|
||||
var template = require('../dist/template-native-debug.js');
|
||||
module.exports = node(template);
|
||||
9
public/static/libs/art-template/node/template.js
Normal file
@@ -0,0 +1,9 @@
|
||||
/*!
|
||||
* artTemplate[NodeJS]
|
||||
* https://github.com/aui/artTemplate
|
||||
* Released under the MIT, BSD, and GPL Licenses
|
||||
*/
|
||||
|
||||
var node = require('./_node.js');
|
||||
var template = require('../dist/template-debug.js');
|
||||
module.exports = node(template);
|
||||
29
public/static/libs/art-template/package.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "art-template",
|
||||
"description": "JavaScript Template Engine",
|
||||
"version": "3.1.3",
|
||||
"homepage": "http://aui.github.com/artTemplate/",
|
||||
"keywords": [
|
||||
"util",
|
||||
"functional",
|
||||
"template"
|
||||
],
|
||||
"author": "tangbin <sugarpie.tang@gmail.com>",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/aui/artTemplate.git"
|
||||
},
|
||||
"main": "./node/template.js",
|
||||
"devDependencies": {
|
||||
"express": "~4.4.3",
|
||||
"grunt-cli": "*",
|
||||
"grunt": "*",
|
||||
"grunt-contrib-jshint": "*",
|
||||
"grunt-contrib-concat": "*",
|
||||
"grunt-contrib-uglify": "*"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "grunt"
|
||||
},
|
||||
"license": "BSD"
|
||||
}
|
||||
3
public/static/libs/art-template/src/cache.js
Normal file
@@ -0,0 +1,3 @@
|
||||
var cacheStore = template.cache = {};
|
||||
|
||||
|
||||
366
public/static/libs/art-template/src/compile.js
Normal file
@@ -0,0 +1,366 @@
|
||||
/**
|
||||
* 编译模板
|
||||
* 2012-6-6 @TooBug: define 方法名改为 compile,与 Node Express 保持一致
|
||||
* @name template.compile
|
||||
* @param {String} 模板字符串
|
||||
* @param {Object} 编译选项
|
||||
*
|
||||
* - openTag {String}
|
||||
* - closeTag {String}
|
||||
* - filename {String}
|
||||
* - escape {Boolean}
|
||||
* - compress {Boolean}
|
||||
* - debug {Boolean}
|
||||
* - cache {Boolean}
|
||||
* - parser {Function}
|
||||
*
|
||||
* @return {Function} 渲染方法
|
||||
*/
|
||||
var compile = template.compile = function (source, options) {
|
||||
|
||||
// 合并默认配置
|
||||
options = options || {};
|
||||
for (var name in defaults) {
|
||||
if (options[name] === undefined) {
|
||||
options[name] = defaults[name];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var filename = options.filename;
|
||||
|
||||
|
||||
try {
|
||||
|
||||
var Render = compiler(source, options);
|
||||
|
||||
} catch (e) {
|
||||
|
||||
e.filename = filename || 'anonymous';
|
||||
e.name = 'Syntax Error';
|
||||
|
||||
return showDebugInfo(e);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 对编译结果进行一次包装
|
||||
|
||||
function render (data) {
|
||||
|
||||
try {
|
||||
|
||||
return new Render(data, filename) + '';
|
||||
|
||||
} catch (e) {
|
||||
|
||||
// 运行时出错后自动开启调试模式重新编译
|
||||
if (!options.debug) {
|
||||
options.debug = true;
|
||||
return compile(source, options)(data);
|
||||
}
|
||||
|
||||
return showDebugInfo(e)();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
render.prototype = Render.prototype;
|
||||
render.toString = function () {
|
||||
return Render.toString();
|
||||
};
|
||||
|
||||
|
||||
if (filename && options.cache) {
|
||||
cacheStore[filename] = render;
|
||||
}
|
||||
|
||||
|
||||
return render;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// 数组迭代
|
||||
var forEach = utils.$each;
|
||||
|
||||
|
||||
// 静态分析模板变量
|
||||
var KEYWORDS =
|
||||
// 关键字
|
||||
'break,case,catch,continue,debugger,default,delete,do,else,false'
|
||||
+ ',finally,for,function,if,in,instanceof,new,null,return,switch,this'
|
||||
+ ',throw,true,try,typeof,var,void,while,with'
|
||||
|
||||
// 保留字
|
||||
+ ',abstract,boolean,byte,char,class,const,double,enum,export,extends'
|
||||
+ ',final,float,goto,implements,import,int,interface,long,native'
|
||||
+ ',package,private,protected,public,short,static,super,synchronized'
|
||||
+ ',throws,transient,volatile'
|
||||
|
||||
// ECMA 5 - use strict
|
||||
+ ',arguments,let,yield'
|
||||
|
||||
+ ',undefined';
|
||||
|
||||
var REMOVE_RE = /\/\*[\w\W]*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|"(?:[^"\\]|\\[\w\W])*"|'(?:[^'\\]|\\[\w\W])*'|\s*\.\s*[$\w\.]+/g;
|
||||
var SPLIT_RE = /[^\w$]+/g;
|
||||
var KEYWORDS_RE = new RegExp(["\\b" + KEYWORDS.replace(/,/g, '\\b|\\b') + "\\b"].join('|'), 'g');
|
||||
var NUMBER_RE = /^\d[^,]*|,\d[^,]*/g;
|
||||
var BOUNDARY_RE = /^,+|,+$/g;
|
||||
var SPLIT2_RE = /^$|,+/;
|
||||
|
||||
|
||||
// 获取变量
|
||||
function getVariable (code) {
|
||||
return code
|
||||
.replace(REMOVE_RE, '')
|
||||
.replace(SPLIT_RE, ',')
|
||||
.replace(KEYWORDS_RE, '')
|
||||
.replace(NUMBER_RE, '')
|
||||
.replace(BOUNDARY_RE, '')
|
||||
.split(SPLIT2_RE);
|
||||
};
|
||||
|
||||
|
||||
// 字符串转义
|
||||
function stringify (code) {
|
||||
return "'" + code
|
||||
// 单引号与反斜杠转义
|
||||
.replace(/('|\\)/g, '\\$1')
|
||||
// 换行符转义(windows + linux)
|
||||
.replace(/\r/g, '\\r')
|
||||
.replace(/\n/g, '\\n') + "'";
|
||||
}
|
||||
|
||||
|
||||
function compiler (source, options) {
|
||||
|
||||
var debug = options.debug;
|
||||
var openTag = options.openTag;
|
||||
var closeTag = options.closeTag;
|
||||
var parser = options.parser;
|
||||
var compress = options.compress;
|
||||
var escape = options.escape;
|
||||
|
||||
|
||||
|
||||
var line = 1;
|
||||
var uniq = {$data:1,$filename:1,$utils:1,$helpers:1,$out:1,$line:1};
|
||||
|
||||
|
||||
|
||||
var isNewEngine = ''.trim;// '__proto__' in {}
|
||||
var replaces = isNewEngine
|
||||
? ["$out='';", "$out+=", ";", "$out"]
|
||||
: ["$out=[];", "$out.push(", ");", "$out.join('')"];
|
||||
|
||||
var concat = isNewEngine
|
||||
? "$out+=text;return $out;"
|
||||
: "$out.push(text);";
|
||||
|
||||
var print = "function(){"
|
||||
+ "var text=''.concat.apply('',arguments);"
|
||||
+ concat
|
||||
+ "}";
|
||||
|
||||
var include = "function(filename,data){"
|
||||
+ "data=data||$data;"
|
||||
+ "var text=$utils.$include(filename,data,$filename);"
|
||||
+ concat
|
||||
+ "}";
|
||||
|
||||
var headerCode = "'use strict';"
|
||||
+ "var $utils=this,$helpers=$utils.$helpers,"
|
||||
+ (debug ? "$line=0," : "");
|
||||
|
||||
var mainCode = replaces[0];
|
||||
|
||||
var footerCode = "return new String(" + replaces[3] + ");"
|
||||
|
||||
// html与逻辑语法分离
|
||||
forEach(source.split(openTag), function (code) {
|
||||
code = code.split(closeTag);
|
||||
|
||||
var $0 = code[0];
|
||||
var $1 = code[1];
|
||||
|
||||
// code: [html]
|
||||
if (code.length === 1) {
|
||||
|
||||
mainCode += html($0);
|
||||
|
||||
// code: [logic, html]
|
||||
} else {
|
||||
|
||||
mainCode += logic($0);
|
||||
|
||||
if ($1) {
|
||||
mainCode += html($1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
var code = headerCode + mainCode + footerCode;
|
||||
|
||||
// 调试语句
|
||||
if (debug) {
|
||||
code = "try{" + code + "}catch(e){"
|
||||
+ "throw {"
|
||||
+ "filename:$filename,"
|
||||
+ "name:'Render Error',"
|
||||
+ "message:e.message,"
|
||||
+ "line:$line,"
|
||||
+ "source:" + stringify(source)
|
||||
+ ".split(/\\n/)[$line-1].replace(/^\\s+/,'')"
|
||||
+ "};"
|
||||
+ "}";
|
||||
}
|
||||
|
||||
|
||||
|
||||
try {
|
||||
|
||||
|
||||
var Render = new Function("$data", "$filename", code);
|
||||
Render.prototype = utils;
|
||||
|
||||
return Render;
|
||||
|
||||
} catch (e) {
|
||||
e.temp = "function anonymous($data,$filename) {" + code + "}";
|
||||
throw e;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 处理 HTML 语句
|
||||
function html (code) {
|
||||
|
||||
// 记录行号
|
||||
line += code.split(/\n/).length - 1;
|
||||
|
||||
// 压缩多余空白与注释
|
||||
if (compress) {
|
||||
code = code
|
||||
.replace(/\s+/g, ' ')
|
||||
.replace(/<!--[\w\W]*?-->/g, '');
|
||||
}
|
||||
|
||||
if (code) {
|
||||
code = replaces[1] + stringify(code) + replaces[2] + "\n";
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
// 处理逻辑语句
|
||||
function logic (code) {
|
||||
|
||||
var thisLine = line;
|
||||
|
||||
if (parser) {
|
||||
|
||||
// 语法转换插件钩子
|
||||
code = parser(code, options);
|
||||
|
||||
} else if (debug) {
|
||||
|
||||
// 记录行号
|
||||
code = code.replace(/\n/g, function () {
|
||||
line ++;
|
||||
return "$line=" + line + ";";
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 输出语句. 编码: <%=value%> 不编码:<%=#value%>
|
||||
// <%=#value%> 等同 v2.0.3 之前的 <%==value%>
|
||||
if (code.indexOf('=') === 0) {
|
||||
|
||||
var escapeSyntax = escape && !/^=[=#]/.test(code);
|
||||
|
||||
code = code.replace(/^=[=#]?|[\s;]*$/g, '');
|
||||
|
||||
// 对内容编码
|
||||
if (escapeSyntax) {
|
||||
|
||||
var name = code.replace(/\s*\([^\)]+\)/, '');
|
||||
|
||||
// 排除 utils.* | include | print
|
||||
|
||||
if (!utils[name] && !/^(include|print)$/.test(name)) {
|
||||
code = "$escape(" + code + ")";
|
||||
}
|
||||
|
||||
// 不编码
|
||||
} else {
|
||||
code = "$string(" + code + ")";
|
||||
}
|
||||
|
||||
|
||||
code = replaces[1] + code + replaces[2];
|
||||
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
code = "$line=" + thisLine + ";" + code;
|
||||
}
|
||||
|
||||
// 提取模板中的变量名
|
||||
forEach(getVariable(code), function (name) {
|
||||
|
||||
// name 值可能为空,在安卓低版本浏览器下
|
||||
if (!name || uniq[name]) {
|
||||
return;
|
||||
}
|
||||
|
||||
var value;
|
||||
|
||||
// 声明模板变量
|
||||
// 赋值优先级:
|
||||
// [include, print] > utils > helpers > data
|
||||
if (name === 'print') {
|
||||
|
||||
value = print;
|
||||
|
||||
} else if (name === 'include') {
|
||||
|
||||
value = include;
|
||||
|
||||
} else if (utils[name]) {
|
||||
|
||||
value = "$utils." + name;
|
||||
|
||||
} else if (helpers[name]) {
|
||||
|
||||
value = "$helpers." + name;
|
||||
|
||||
} else {
|
||||
|
||||
value = "$data." + name;
|
||||
}
|
||||
|
||||
headerCode += name + "=" + value + ",";
|
||||
uniq[name] = true;
|
||||
|
||||
|
||||
});
|
||||
|
||||
return code + "\n";
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
22
public/static/libs/art-template/src/config.js
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 设置全局配置
|
||||
* @name template.config
|
||||
* @param {String} 名称
|
||||
* @param {Any} 值
|
||||
*/
|
||||
template.config = function (name, value) {
|
||||
defaults[name] = value;
|
||||
};
|
||||
|
||||
|
||||
|
||||
var defaults = template.defaults = {
|
||||
openTag: '<%', // 逻辑语法开始标签
|
||||
closeTag: '%>', // 逻辑语法结束标签
|
||||
escape: true, // 是否编码输出变量的 HTML 字符
|
||||
cache: true, // 是否开启缓存(依赖 options 的 filename 字段)
|
||||
compress: false, // 是否压缩输出
|
||||
parser: null // 自定义语法格式器 @see: template-syntax.js
|
||||
};
|
||||
|
||||
|
||||
29
public/static/libs/art-template/src/get.js
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 获取编译缓存(可由外部重写此方法)
|
||||
* @param {String} 模板名
|
||||
* @param {Function} 编译好的函数
|
||||
*/
|
||||
template.get = function (filename) {
|
||||
|
||||
var cache;
|
||||
|
||||
if (cacheStore[filename]) {
|
||||
// 使用内存缓存
|
||||
cache = cacheStore[filename];
|
||||
} else if (typeof document === 'object') {
|
||||
// 加载模板并编译
|
||||
var elem = document.getElementById(filename);
|
||||
|
||||
if (elem) {
|
||||
var source = (elem.value || elem.innerHTML)
|
||||
.replace(/^\s*|\s*$/g, '');
|
||||
cache = compile(source, {
|
||||
filename: filename
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return cache;
|
||||
};
|
||||
|
||||
|
||||
15
public/static/libs/art-template/src/helper.js
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* 添加模板辅助方法
|
||||
* @name template.helper
|
||||
* @param {String} 名称
|
||||
* @param {Function} 方法
|
||||
*/
|
||||
template.helper = function (name, helper) {
|
||||
helpers[name] = helper;
|
||||
};
|
||||
|
||||
var helpers = template.helpers = utils.$helpers;
|
||||
|
||||
|
||||
|
||||
|
||||
9
public/static/libs/art-template/src/intro.js
Normal file
@@ -0,0 +1,9 @@
|
||||
/*!
|
||||
* artTemplate - Template Engine
|
||||
* https://github.com/aui/artTemplate
|
||||
* Released under the MIT, BSD, and GPL Licenses
|
||||
*/
|
||||
|
||||
!(function () {
|
||||
|
||||
|
||||