mirror of
https://github.com/getgrav/grav-plugin-admin.git
synced 2025-11-09 06:46:04 +01:00
Reworked Admin JS with ES6
This commit is contained in:
18
.editorconfig
Normal file
18
.editorconfig
Normal file
@@ -0,0 +1,18 @@
|
||||
# EditorConfig is awesome: http://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
# 2 space indentation
|
||||
[*.yaml, *.yml]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,2 +1,5 @@
|
||||
themes/grav/.sass-cache
|
||||
.DS_Store
|
||||
|
||||
# Node Modules
|
||||
**/node_modules/**
|
||||
|
||||
@@ -571,7 +571,7 @@ class AdminPlugin extends Plugin
|
||||
$this->theme = $this->config->get('plugins.admin.theme', 'grav');
|
||||
|
||||
$assets = $this->grav['assets'];
|
||||
$translations = 'if (!window.translations) window.translations = {}; ' . PHP_EOL . 'window.translations.PLUGIN_ADMIN = {};' . PHP_EOL;
|
||||
$translations = 'this.GravAdmin = this.GravAdmin || {}; if (!this.GravAdmin.translations) this.GravAdmin.translations = {}; ' . PHP_EOL . 'this.GravAdmin.translations.PLUGIN_ADMIN = {';
|
||||
|
||||
// Enable language translations
|
||||
$translations_actual_state = $this->config->get('system.languages.translations');
|
||||
@@ -597,13 +597,16 @@ class AdminPlugin extends Plugin
|
||||
'DAYS',
|
||||
'PAGE_MODES',
|
||||
'PAGE_TYPES',
|
||||
'ACCESS_LEVELS'
|
||||
'ACCESS_LEVELS',
|
||||
'NOTHING_TO_SAVE'
|
||||
];
|
||||
|
||||
foreach($strings as $string) {
|
||||
$translations .= 'translations.PLUGIN_ADMIN.' . $string .' = "' . $this->admin->translate('PLUGIN_ADMIN.' . $string) . '"; ' . PHP_EOL;;
|
||||
$separator = (end($strings) === $string) ? '' : ',';
|
||||
$translations .= '"' . $string .'": "' . $this->admin->translate('PLUGIN_ADMIN.' . $string) . '"' . $separator;
|
||||
}
|
||||
|
||||
$translations .= '};';
|
||||
// set the actual translations state back
|
||||
$this->config->set('system.languages.translations', $translations_actual_state);
|
||||
|
||||
|
||||
@@ -447,6 +447,7 @@ class AdminController
|
||||
'message' => $this->admin->translate('PLUGIN_ADMIN.YOUR_BACKUP_IS_READY_FOR_DOWNLOAD') . '. <a href="'.$url.'" class="button">' . $this->admin->translate('PLUGIN_ADMIN.DOWNLOAD_BACKUP') .'</a>',
|
||||
'toastr' => [
|
||||
'timeOut' => 0,
|
||||
'extendedTimeOut' => 0,
|
||||
'closeButton' => true
|
||||
]
|
||||
];
|
||||
@@ -576,7 +577,7 @@ class AdminController
|
||||
foreach ($page->media()->all() as $name => $media) {
|
||||
$media_list[$name] = ['url' => $media->cropZoom(150, 100)->url(), 'size' => $media->get('size')];
|
||||
}
|
||||
$this->admin->json_response = ['status' => 'ok', 'results' => $media_list];
|
||||
$this->admin->json_response = ['status' => 'success', 'results' => $media_list];
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -646,6 +647,7 @@ class AdminController
|
||||
return false;
|
||||
}
|
||||
|
||||
Cache::clearCache();
|
||||
$this->admin->json_response = ['status' => 'success', 'message' => $this->admin->translate('PLUGIN_ADMIN.FILE_UPLOADED_SUCCESSFULLY')];
|
||||
|
||||
return true;
|
||||
@@ -675,6 +677,7 @@ class AdminController
|
||||
|
||||
if (file_exists($targetPath)) {
|
||||
if (unlink($targetPath)) {
|
||||
Cache::clearCache();
|
||||
$this->admin->json_response = ['status' => 'success', 'message' => $this->admin->translate('PLUGIN_ADMIN.FILE_DELETED') . ': '.$filename];
|
||||
} else {
|
||||
$this->admin->json_response = ['status' => 'error', 'message' => $this->admin->translate('PLUGIN_ADMIN.FILE_COULD_NOT_BE_DELETED') . ': '.$filename];
|
||||
@@ -701,6 +704,7 @@ class AdminController
|
||||
}
|
||||
|
||||
if ($deletedResponsiveImage) {
|
||||
Cache::clearCache();
|
||||
$this->admin->json_response = ['status' => 'success', 'message' => $this->admin->translate('PLUGIN_ADMIN.FILE_DELETED') . ': '.$filename];
|
||||
} else {
|
||||
$this->admin->json_response = ['status' => 'error', 'message' => $this->admin->translate('PLUGIN_ADMIN.FILE_NOT_FOUND') . ': '.$filename];
|
||||
@@ -887,9 +891,9 @@ class AdminController
|
||||
$result = \Grav\Plugin\Admin\Gpm::selfupgrade();
|
||||
|
||||
if ($result) {
|
||||
$this->admin->json_response = ['status' => 'success', 'message' => $this->admin->translate('PLUGIN_ADMIN.GRAV_WAS_SUCCESSFULLY_UPDATED_TO') . ' '];
|
||||
$this->admin->json_response = ['status' => 'success', 'type' => 'updategrav', 'version' => GRAV_VERSION, 'message' => $this->admin->translate('PLUGIN_ADMIN.GRAV_WAS_SUCCESSFULLY_UPDATED_TO') . ' ' . GRAV_VERSION];
|
||||
} else {
|
||||
$this->admin->json_response = ['status' => 'error', 'message' => $this->admin->translate('PLUGIN_ADMIN.GRAV_UPDATE_FAILED') . ' <br>' . Installer::lastErrorMsg()];
|
||||
$this->admin->json_response = ['status' => 'error', 'type' => 'updategrav', 'version' => GRAV_VERSION, 'message' => $this->admin->translate('PLUGIN_ADMIN.GRAV_UPDATE_FAILED') . ' <br>' . Installer::lastErrorMsg()];
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -935,9 +939,9 @@ class AdminController
|
||||
if ($this->view === 'update') {
|
||||
|
||||
if ($result) {
|
||||
$this->admin->json_response = ['status' => 'success', 'message' => $this->admin->translate('PLUGIN_ADMIN.EVERYTHING_UPDATED')];
|
||||
$this->admin->json_response = ['status' => 'success', 'type' => 'update', 'message' => $this->admin->translate('PLUGIN_ADMIN.EVERYTHING_UPDATED')];
|
||||
} else {
|
||||
$this->admin->json_response = ['status' => 'error', 'message' => $this->admin->translate('PLUGIN_ADMIN.UPDATES_FAILED')];
|
||||
$this->admin->json_response = ['status' => 'error', 'type' => 'update', 'message' => $this->admin->translate('PLUGIN_ADMIN.UPDATES_FAILED')];
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
@@ -130,7 +130,7 @@ class Popularity
|
||||
$data[] = $count;
|
||||
}
|
||||
|
||||
return array('labels' => json_encode($labels), 'data' => json_encode($data));
|
||||
return array('labels' => $labels, 'data' => $data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -475,3 +475,5 @@ PLUGIN_ADMIN:
|
||||
REVERSE_PROXY: "Reverse Proxy"
|
||||
REVERSE_PROXY_HELP: "Enable this if you are behind a reverse proxy and you are having trouble with URLs containing incorrect ports"
|
||||
INVALID_FRONTMATTER_COULD_NOT_SAVE: "Invalid frontmatter, could not save"
|
||||
NOTHING_TO_SAVE: "Nothing to Save"
|
||||
|
||||
|
||||
181
themes/grav/.eslintrc
Normal file
181
themes/grav/.eslintrc
Normal file
@@ -0,0 +1,181 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true
|
||||
},
|
||||
|
||||
"ecmaFeatures": {
|
||||
"arrowFunctions": true,
|
||||
"destructuring": true,
|
||||
"classes": true,
|
||||
"defaultParams": true,
|
||||
"blockBindings": true,
|
||||
"modules": true,
|
||||
"objectLiteralComputedProperties": true,
|
||||
"objectLiteralShorthandMethods": true,
|
||||
"objectLiteralShorthandProperties": true,
|
||||
"restParams": true,
|
||||
"spread": true,
|
||||
"forOf": true,
|
||||
"generators": true,
|
||||
"templateStrings": true,
|
||||
"superInFunctions": true,
|
||||
"experimentalObjectRestSpread": true
|
||||
},
|
||||
|
||||
"rules": {
|
||||
"accessor-pairs": 2,
|
||||
"array-bracket-spacing": 0,
|
||||
"block-scoped-var": 0,
|
||||
"brace-style": [2, "1tbs", { "allowSingleLine": true }],
|
||||
"camelcase": 0,
|
||||
"comma-dangle": [2, "never"],
|
||||
"comma-spacing": [2, { "before": false, "after": true }],
|
||||
"comma-style": [2, "last"],
|
||||
"complexity": 0,
|
||||
"computed-property-spacing": 0,
|
||||
"consistent-return": 0,
|
||||
"consistent-this": 0,
|
||||
"constructor-super": 2,
|
||||
"curly": [2, "multi-line"],
|
||||
"default-case": 0,
|
||||
"dot-location": [2, "property"],
|
||||
"dot-notation": 0,
|
||||
"eol-last": 2,
|
||||
"eqeqeq": [2, "allow-null"],
|
||||
"func-names": 0,
|
||||
"func-style": 0,
|
||||
"generator-star-spacing": [2, { "before": true, "after": true }],
|
||||
"guard-for-in": 0,
|
||||
"handle-callback-err": [2, "^(err|error)$" ],
|
||||
"indent": [2, 4, { "SwitchCase": 1 }],
|
||||
"key-spacing": [2, { "beforeColon": false, "afterColon": true }],
|
||||
"linebreak-style": 0,
|
||||
"lines-around-comment": 0,
|
||||
"max-nested-callbacks": 0,
|
||||
"new-cap": [2, { "newIsCap": true, "capIsNew": false }],
|
||||
"new-parens": 2,
|
||||
"newline-after-var": 0,
|
||||
"no-alert": 0,
|
||||
"no-array-constructor": 2,
|
||||
"no-caller": 2,
|
||||
"no-catch-shadow": 0,
|
||||
"no-cond-assign": 2,
|
||||
"no-console": 0,
|
||||
"no-constant-condition": 0,
|
||||
"no-continue": 0,
|
||||
"no-control-regex": 2,
|
||||
"no-debugger": 2,
|
||||
"no-delete-var": 2,
|
||||
"no-div-regex": 0,
|
||||
"no-dupe-args": 2,
|
||||
"no-dupe-keys": 2,
|
||||
"no-duplicate-case": 2,
|
||||
"no-else-return": 0,
|
||||
"no-empty": 0,
|
||||
"no-empty-character-class": 2,
|
||||
"no-empty-label": 2,
|
||||
"no-eq-null": 0,
|
||||
"no-eval": 2,
|
||||
"no-ex-assign": 2,
|
||||
"no-extend-native": 2,
|
||||
"no-extra-bind": 2,
|
||||
"no-extra-boolean-cast": 2,
|
||||
"no-extra-parens": 0,
|
||||
"no-extra-semi": 0,
|
||||
"no-fallthrough": 2,
|
||||
"no-floating-decimal": 2,
|
||||
"no-func-assign": 2,
|
||||
"no-implied-eval": 2,
|
||||
"no-inline-comments": 0,
|
||||
"no-inner-declarations": [2, "functions"],
|
||||
"no-invalid-regexp": 2,
|
||||
"no-irregular-whitespace": 2,
|
||||
"no-iterator": 2,
|
||||
"no-label-var": 2,
|
||||
"no-labels": 2,
|
||||
"no-lone-blocks": 2,
|
||||
"no-lonely-if": 0,
|
||||
"no-loop-func": 0,
|
||||
"no-mixed-requires": 0,
|
||||
"no-mixed-spaces-and-tabs": 2,
|
||||
"no-multi-spaces": 2,
|
||||
"no-multi-str": 2,
|
||||
"no-multiple-empty-lines": [2, { "max": 1 }],
|
||||
"no-native-reassign": 2,
|
||||
"no-negated-in-lhs": 2,
|
||||
"no-nested-ternary": 0,
|
||||
"no-new": 2,
|
||||
"no-new-func": 0,
|
||||
"no-new-object": 2,
|
||||
"no-new-require": 2,
|
||||
"no-new-wrappers": 2,
|
||||
"no-obj-calls": 2,
|
||||
"no-octal": 2,
|
||||
"no-octal-escape": 2,
|
||||
"no-param-reassign": 0,
|
||||
"no-path-concat": 0,
|
||||
"no-process-env": 0,
|
||||
"no-process-exit": 0,
|
||||
"no-proto": 0,
|
||||
"no-redeclare": 2,
|
||||
"no-regex-spaces": 2,
|
||||
"no-restricted-modules": 0,
|
||||
"no-return-assign": 2,
|
||||
"no-script-url": 0,
|
||||
"no-self-compare": 2,
|
||||
"no-sequences": 2,
|
||||
"no-shadow": 0,
|
||||
"no-shadow-restricted-names": 2,
|
||||
"no-spaced-func": 2,
|
||||
"no-sparse-arrays": 2,
|
||||
"no-sync": 0,
|
||||
"no-ternary": 0,
|
||||
"no-this-before-super": 2,
|
||||
"no-throw-literal": 2,
|
||||
"no-trailing-spaces": 2,
|
||||
"no-undef": 2,
|
||||
"no-undef-init": 2,
|
||||
"no-undefined": 0,
|
||||
"no-underscore-dangle": 0,
|
||||
"no-unexpected-multiline": 2,
|
||||
"no-unneeded-ternary": 2,
|
||||
"no-unreachable": 2,
|
||||
"no-unused-expressions": 0,
|
||||
"no-unused-vars": [2, { "vars": "all", "args": "none" }],
|
||||
"no-use-before-define": 0,
|
||||
"no-var": 0,
|
||||
"no-void": 0,
|
||||
"no-warning-comments": 0,
|
||||
"no-with": 2,
|
||||
"object-curly-spacing": 0,
|
||||
"object-shorthand": 0,
|
||||
"one-var": [2, { "initialized": "never" }],
|
||||
"operator-assignment": 0,
|
||||
"operator-linebreak": [2, "after", { "overrides": { "?": "before", ":": "before" } }],
|
||||
"padded-blocks": 0,
|
||||
"prefer-const": 0,
|
||||
"quote-props": 0,
|
||||
"quotes": [2, "single", "avoid-escape"],
|
||||
"radix": 2,
|
||||
"semi": [2, "always"],
|
||||
"semi-spacing": 0,
|
||||
"sort-vars": 0,
|
||||
"space-after-keywords": [2, "always"],
|
||||
"space-before-blocks": [2, "always"],
|
||||
"space-before-function-paren": [2, "never"],
|
||||
"space-in-parens": [2, "never"],
|
||||
"space-infix-ops": 2,
|
||||
"space-return-throw-case": 2,
|
||||
"space-unary-ops": [2, { "words": true, "nonwords": false }],
|
||||
"spaced-comment": [2, "always", { "markers": ["global", "globals", "eslint", "eslint-disable", "*package", "!"] }],
|
||||
"strict": 0,
|
||||
"use-isnan": 2,
|
||||
"valid-jsdoc": 0,
|
||||
"valid-typeof": 2,
|
||||
"vars-on-top": 0,
|
||||
"wrap-iife": [2, "any"],
|
||||
"wrap-regex": 0,
|
||||
"yoda": [2, "never"]
|
||||
}
|
||||
}
|
||||
24
themes/grav/app/dashboard/backup.js
Normal file
24
themes/grav/app/dashboard/backup.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import $ from 'jquery';
|
||||
import { translations } from 'grav-config';
|
||||
import request from '../utils/request';
|
||||
import { Instances as Charts } from './chart';
|
||||
|
||||
$('[data-ajax*="task:backup"]').on('click', function() {
|
||||
let element = $(this);
|
||||
let url = element.data('ajax');
|
||||
|
||||
element
|
||||
.attr('disabled', 'disabled')
|
||||
.find('> .fa').removeClass('fa-database').addClass('fa-spin fa-refresh');
|
||||
|
||||
request(url, (/* response */) => {
|
||||
if (Charts && Charts.backups) {
|
||||
Charts.backups.updateData({ series: [0, 100] });
|
||||
Charts.backups.element.find('.numeric').html(`0 <em>${translations.PLUGIN_ADMIN.DAYS.toLowerCase()}</em>`);
|
||||
}
|
||||
|
||||
element
|
||||
.removeAttr('disabled')
|
||||
.find('> .fa').removeClass('fa-spin fa-refresh').addClass('fa-database');
|
||||
});
|
||||
});
|
||||
49
themes/grav/app/dashboard/cache.js
Normal file
49
themes/grav/app/dashboard/cache.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import $ from 'jquery';
|
||||
import { config } from 'grav-config';
|
||||
import request from '../utils/request';
|
||||
|
||||
const getUrl = (type = '') => {
|
||||
if (type) {
|
||||
type = `cleartype:${type}/`;
|
||||
}
|
||||
|
||||
return `${config.base_url_relative}/cache.json/task:clearCache/${type}admin-nonce:${config.admin_nonce}`;
|
||||
};
|
||||
|
||||
export default class Cache {
|
||||
constructor() {
|
||||
this.element = $('[data-clear-cache]');
|
||||
$('body').on('click', '[data-clear-cache]', (event) => this.clear(event, event.target));
|
||||
}
|
||||
|
||||
clear(event, element) {
|
||||
let type = '';
|
||||
|
||||
if (event && event.preventDefault) { event.preventDefault(); }
|
||||
if (typeof event === 'string') { type = event; }
|
||||
|
||||
element = element ? $(element) : $(`[data-clear-cache-type="${type}"]`);
|
||||
type = type || $(element).data('clear-cache-type') || '';
|
||||
let url = element.data('clearCache') || getUrl(event);
|
||||
|
||||
this.disable();
|
||||
|
||||
request(url, () => this.enable());
|
||||
}
|
||||
|
||||
enable() {
|
||||
this.element
|
||||
.removeAttr('disabled')
|
||||
.find('> .fa').removeClass('fa-refresh fa-spin').addClass('fa-trash');
|
||||
}
|
||||
|
||||
disable() {
|
||||
this.element
|
||||
.attr('disabled', 'disabled')
|
||||
.find('> .fa').removeClass('fa-trash').addClass('fa-refresh fa-spin');
|
||||
}
|
||||
}
|
||||
|
||||
let Instance = new Cache();
|
||||
|
||||
export { Instance };
|
||||
124
themes/grav/app/dashboard/chart.js
Normal file
124
themes/grav/app/dashboard/chart.js
Normal file
@@ -0,0 +1,124 @@
|
||||
import $ from 'jquery';
|
||||
import chartist from 'chartist';
|
||||
import { translations } from 'grav-config';
|
||||
import { Instance as gpm } from '../utils/gpm';
|
||||
import { Instance as updates } from '../updates';
|
||||
|
||||
let isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
||||
|
||||
export const defaults = {
|
||||
data: {
|
||||
series: [100, 0]
|
||||
},
|
||||
options: {
|
||||
Pie: {
|
||||
donut: true,
|
||||
donutWidth: 10,
|
||||
startAngle: 0,
|
||||
total: 100,
|
||||
showLabel: false,
|
||||
height: 150,
|
||||
chartPadding: !isFirefox ? 10 : 25
|
||||
},
|
||||
Bar: {
|
||||
height: 164,
|
||||
chartPadding: !isFirefox ? 5 : 25,
|
||||
|
||||
axisX: {
|
||||
showGrid: false,
|
||||
labelOffset: {
|
||||
x: 0,
|
||||
y: 5
|
||||
}
|
||||
},
|
||||
axisY: {
|
||||
offset: 15,
|
||||
showLabel: true,
|
||||
showGrid: true,
|
||||
labelOffset: {
|
||||
x: 5,
|
||||
y: 5
|
||||
},
|
||||
scaleMinSpace: 20
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default class Chart {
|
||||
constructor(element, options = {}, data = {}) {
|
||||
this.element = $(element) || [];
|
||||
if (!this.element[0]) { return; }
|
||||
|
||||
let type = (this.element.data('chart-type') || 'pie').toLowerCase();
|
||||
this.type = type.charAt(0).toUpperCase() + type.substr(1).toLowerCase();
|
||||
|
||||
options = Object.assign({}, defaults.options[this.type], options);
|
||||
data = Object.assign({}, defaults.data, data);
|
||||
Object.assign(this, {
|
||||
options,
|
||||
data
|
||||
});
|
||||
this.chart = chartist[this.type](this.element.find('.ct-chart')[0], this.data, this.options);
|
||||
}
|
||||
|
||||
updateData(data) {
|
||||
Object.assign(this.data, data);
|
||||
this.chart.update(this.data);
|
||||
}
|
||||
};
|
||||
|
||||
export class UpdatesChart extends Chart {
|
||||
constructor(element, options = {}, data = {}) {
|
||||
super(element, options, data);
|
||||
|
||||
this.chart.on('draw', (data) => this.draw(data));
|
||||
|
||||
gpm.on('fetched', (response) => {
|
||||
let payload = response.payload.grav;
|
||||
let missing = (response.payload.resources.total + (payload.isUpdatable ? 1 : 0)) * 100 / (response.payload.installed + (payload.isUpdatable ? 1 : 0));
|
||||
let updated = 100 - missing;
|
||||
|
||||
this.updateData({ series: [updated, missing] });
|
||||
|
||||
if (response.payload.resources.total) {
|
||||
updates.maintenance('show');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
draw(data) {
|
||||
if (data.index) { return; }
|
||||
|
||||
let notice = translations.PLUGIN_ADMIN[data.value === 100 ? 'FULLY_UPDATED' : 'UPDATES_AVAILABLE'];
|
||||
this.element.find('.numeric span').text(`${Math.round(data.value)}%`);
|
||||
this.element.find('.js__updates-available-description').html(notice);
|
||||
this.element.find('.hidden').removeClass('hidden');
|
||||
}
|
||||
|
||||
updateData(data) {
|
||||
super.updateData(data);
|
||||
|
||||
// missing updates
|
||||
if (this.data.series[0] < 100) {
|
||||
this.element.closest('#updates').find('[data-maintenance-update]').fadeIn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let charts = {};
|
||||
|
||||
$('[data-chart-name]').each(function() {
|
||||
let element = $(this);
|
||||
let name = element.data('chart-name') || '';
|
||||
let options = element.data('chart-options') || {};
|
||||
let data = element.data('chart-data') || {};
|
||||
|
||||
if (name === 'updates') {
|
||||
charts[name] = new UpdatesChart(element, options, data);
|
||||
} else {
|
||||
charts[name] = new Chart(element, options, data);
|
||||
}
|
||||
});
|
||||
|
||||
export let Instances = charts;
|
||||
12
themes/grav/app/dashboard/index.js
Normal file
12
themes/grav/app/dashboard/index.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import Chart, { UpdatesChart, Instances } from './chart';
|
||||
import { Instance as Cache } from './cache';
|
||||
import './backup';
|
||||
|
||||
export default {
|
||||
Chart: {
|
||||
Chart,
|
||||
UpdatesChart,
|
||||
Instances
|
||||
},
|
||||
Cache
|
||||
};
|
||||
1
themes/grav/app/dashboard/update.js
Normal file
1
themes/grav/app/dashboard/update.js
Normal file
@@ -0,0 +1 @@
|
||||
// See ../updates/update.js
|
||||
146
themes/grav/app/forms/fields/array.js
Normal file
146
themes/grav/app/forms/fields/array.js
Normal file
@@ -0,0 +1,146 @@
|
||||
import $ from 'jquery';
|
||||
|
||||
let body = $('body');
|
||||
|
||||
class Template {
|
||||
constructor(container) {
|
||||
this.container = $(container);
|
||||
|
||||
if (this.getName() === undefined) {
|
||||
this.container = this.container.closest('[data-grav-array-name]');
|
||||
}
|
||||
}
|
||||
|
||||
getName() {
|
||||
return this.container.data('grav-array-name') || '';
|
||||
}
|
||||
|
||||
getKeyPlaceholder() {
|
||||
return this.container.data('grav-array-keyname') || 'Key';
|
||||
}
|
||||
|
||||
getValuePlaceholder() {
|
||||
return this.container.data('grav-array-valuename') || 'Value';
|
||||
}
|
||||
|
||||
isValueOnly() {
|
||||
return this.container.find('[data-grav-array-mode="value_only"]:first').length || false;
|
||||
}
|
||||
|
||||
shouldBeDisabled() {
|
||||
// check for toggleables, if field is toggleable and it's not enabled, render disabled
|
||||
let toggle = this.container.closest('.form-field').find('[data-grav-field="toggleable"] input[type="checkbox"]');
|
||||
return toggle.length && toggle.is(':not(:checked)');
|
||||
}
|
||||
|
||||
getNewRow() {
|
||||
let tpl = '';
|
||||
|
||||
if (this.isValueOnly()) {
|
||||
tpl += `
|
||||
<div class="form-row array-field-value_only" data-grav-array-type="row">
|
||||
<input ${this.shouldBeDisabled() ? 'disabled="disabled"' : ''} data-grav-array-type="value" type="text" value="" placeholder="${this.getValuePlaceholder()}" />
|
||||
`;
|
||||
} else {
|
||||
tpl += `
|
||||
<div class="form-row" data-grav-array-type="row">
|
||||
<input ${this.shouldBeDisabled() ? 'disabled="disabled"' : ''} data-grav-array-type="key" type="text" value="" placeholder="${this.getKeyPlaceholder()}" />
|
||||
<input ${this.shouldBeDisabled() ? 'disabled="disabled"' : ''} data-grav-array-type="value" type="text" name="" value="" placeholder="${this.getValuePlaceholder()}" />
|
||||
`;
|
||||
}
|
||||
|
||||
tpl += `
|
||||
<span data-grav-array-action="rem" class="fa fa-minus"></span>
|
||||
<span data-grav-array-action="add" class="fa fa-plus"></span>
|
||||
</div>`;
|
||||
|
||||
return tpl;
|
||||
}
|
||||
}
|
||||
|
||||
export default class ArrayField {
|
||||
constructor() {
|
||||
body.on('input', '[data-grav-array-type="key"], [data-grav-array-type="value"]', (event) => this.actionInput(event));
|
||||
body.on('click touch', '[data-grav-array-action]', (event) => this.actionEvent(event));
|
||||
}
|
||||
|
||||
actionInput(event) {
|
||||
let element = $(event.target);
|
||||
let type = element.data('grav-array-type');
|
||||
|
||||
this._setTemplate(element);
|
||||
|
||||
let template = element.data('array-template');
|
||||
let keyElement = type === 'key' ? element : element.siblings('[data-grav-array-type="key"]:first');
|
||||
let valueElement = type === 'value' ? element : element.siblings('[data-grav-array-type="value"]:first');
|
||||
|
||||
let name = `${template.getName()}[${!template.isValueOnly() ? keyElement.val() : this.getIndexFor(element)}]`;
|
||||
valueElement.attr('name', !valueElement.val() ? template.getName() : name);
|
||||
|
||||
this.refreshNames(template);
|
||||
}
|
||||
|
||||
actionEvent(event) {
|
||||
let element = $(event.target);
|
||||
let action = element.data('grav-array-action');
|
||||
|
||||
this._setTemplate(element);
|
||||
|
||||
this[`${action}Action`](element);
|
||||
}
|
||||
|
||||
addAction(element) {
|
||||
let template = element.data('array-template');
|
||||
let row = element.closest('[data-grav-array-type="row"]');
|
||||
|
||||
row.after(template.getNewRow());
|
||||
}
|
||||
|
||||
remAction(element) {
|
||||
let template = element.data('array-template');
|
||||
let row = element.closest('[data-grav-array-type="row"]');
|
||||
let isLast = !row.siblings().length;
|
||||
|
||||
if (isLast) {
|
||||
let newRow = $(template.getNewRow());
|
||||
row.after(newRow);
|
||||
newRow.find('[data-grav-array-type="value"]:last').attr('name', template.getName());
|
||||
}
|
||||
|
||||
row.remove();
|
||||
this.refreshNames(template);
|
||||
}
|
||||
|
||||
refreshNames(template) {
|
||||
if (!template.isValueOnly()) { return; }
|
||||
|
||||
let row = template.container.find('> div > [data-grav-array-type="row"]');
|
||||
let inputs = row.find('[name]:not([name=""])');
|
||||
|
||||
inputs.each((index, input) => {
|
||||
input = $(input);
|
||||
let name = input.attr('name');
|
||||
name = name.replace(/\[\d+\]$/, `[${index}]`);
|
||||
input.attr('name', name);
|
||||
});
|
||||
|
||||
if (!inputs.length) {
|
||||
row.find('[data-grav-array-type="value"]').attr('name', template.getName());
|
||||
}
|
||||
}
|
||||
|
||||
getIndexFor(element) {
|
||||
let template = element.data('array-template');
|
||||
let row = element.closest('[data-grav-array-type="row"]');
|
||||
|
||||
return template.container.find(`${template.isValueOnly() ? '> div ' : ''} > [data-grav-array-type="row"]`).index(row);
|
||||
}
|
||||
|
||||
_setTemplate(element) {
|
||||
if (!element.data('array-template')) {
|
||||
element.data('array-template', new Template(element.closest('[data-grav-array-name]')));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export let Instance = new ArrayField();
|
||||
98
themes/grav/app/forms/fields/collections.js
Normal file
98
themes/grav/app/forms/fields/collections.js
Normal file
@@ -0,0 +1,98 @@
|
||||
import $ from 'jquery';
|
||||
import Sortable from 'sortablejs';
|
||||
import '../../utils/jquery-utils';
|
||||
|
||||
export default class CollectionsField {
|
||||
constructor() {
|
||||
this.lists = $();
|
||||
|
||||
$('[data-type="collection"]').each((index, list) => this.addList(list));
|
||||
$('body').on('mutation._grav', this._onAddedNodes.bind(this));
|
||||
|
||||
}
|
||||
|
||||
addList(list) {
|
||||
list = $(list);
|
||||
this.lists = this.lists.add(list);
|
||||
|
||||
list.on('click', '> .collection-actions [data-action="add"]', (event) => this.addItem(event));
|
||||
list.on('click', '> ul > li > .item-actions [data-action="delete"]', (event) => this.removeItem(event));
|
||||
|
||||
list.find('[data-collection-holder]').each((index, container) => {
|
||||
container = $(container);
|
||||
if (container.data('collection-sort')) { return; }
|
||||
|
||||
container.data('collection-sort', new Sortable(container.get(0), {
|
||||
forceFallback: true,
|
||||
animation: 150,
|
||||
onUpdate: () => this.reindex(container)
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
addItem(event) {
|
||||
let button = $(event.currentTarget);
|
||||
let list = button.closest('[data-type="collection"]');
|
||||
let template = $(list.find('> [data-collection-template="new"]').data('collection-template-html'));
|
||||
|
||||
list.find('> [data-collection-holder]').append(template);
|
||||
this.reindex(list);
|
||||
// button.data('key-index', keyIndex + 1);
|
||||
|
||||
// process markdown editors
|
||||
/* var field = template.find('[name]').filter('textarea');
|
||||
if (field.length && field.data('grav-mdeditor') && typeof MDEditors !== 'undefined') {
|
||||
MDEditors.add(field);
|
||||
}*/
|
||||
}
|
||||
|
||||
removeItem(event) {
|
||||
let button = $(event.currentTarget);
|
||||
let item = button.closest('[data-collection-item]');
|
||||
let list = button.closest('[data-type="collection"]');
|
||||
|
||||
item.remove();
|
||||
this.reindex(list);
|
||||
}
|
||||
|
||||
reindex(list) {
|
||||
list = $(list).closest('[data-type="collection"]');
|
||||
|
||||
let items = list.find('> ul > [data-collection-item]');
|
||||
|
||||
items.each((index, item) => {
|
||||
item = $(item);
|
||||
item.attr('data-collection-key', index);
|
||||
|
||||
['name', 'data-grav-field-name', 'id', 'for'].forEach((prop) => {
|
||||
item.find('[' + prop + ']').each(function() {
|
||||
let element = $(this);
|
||||
let indexes = [];
|
||||
element.parents('[data-collection-key]').map((idx, parent) => indexes.push($(parent).attr('data-collection-key')));
|
||||
indexes.reverse();
|
||||
|
||||
let replaced = element.attr(prop).replace(/\[(\d+|\*)\]/g, (/* str, p1, offset */) => {
|
||||
return `[${indexes.shift()}]`;
|
||||
});
|
||||
|
||||
element.attr(prop, replaced);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
_onAddedNodes(event, target/* , record, instance */) {
|
||||
let collections = $(target).find('[data-type="collection"]');
|
||||
if (!collections.length) { return; }
|
||||
|
||||
collections.each((index, collection) => {
|
||||
collection = $(collection);
|
||||
if (!~this.lists.index(collection)) {
|
||||
this.addList(collection);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export let Instance = new CollectionsField();
|
||||
18
themes/grav/app/forms/fields/index.js
Normal file
18
themes/grav/app/forms/fields/index.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import SelectizeField, { Instance as SelectizeFieldInstance } from './selectize';
|
||||
import ArrayField, { Instance as ArrayFieldInstance } from './array';
|
||||
import CollectionsField, { Instance as CollectionsFieldInstance } from './collections';
|
||||
|
||||
export default {
|
||||
SelectizeField: {
|
||||
SelectizeField,
|
||||
Instance: SelectizeFieldInstance
|
||||
},
|
||||
ArrayField: {
|
||||
ArrayField,
|
||||
Instance: ArrayFieldInstance
|
||||
},
|
||||
CollectionsField: {
|
||||
CollectionsField,
|
||||
Instance: CollectionsFieldInstance
|
||||
}
|
||||
};
|
||||
35
themes/grav/app/forms/fields/selectize.js
Normal file
35
themes/grav/app/forms/fields/selectize.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import $ from 'jquery';
|
||||
import 'selectize';
|
||||
|
||||
export default class SelectizeField {
|
||||
constructor(options = {}) {
|
||||
this.options = Object.assign({}, options);
|
||||
this.elements = [];
|
||||
|
||||
$('[data-grav-selectize]').each((index, element) => this.add(element));
|
||||
$('body').on('mutation._grav', this._onAddedNodes.bind(this));
|
||||
}
|
||||
|
||||
add(element) {
|
||||
element = $(element);
|
||||
let tag = element.prop('tagName').toLowerCase();
|
||||
let isInput = tag === 'input' || tag === 'select';
|
||||
|
||||
let data = (isInput ? element.closest('[data-grav-selectize]') : element).data('grav-selectize') || {};
|
||||
let field = (isInput ? element : element.find('input, select'));
|
||||
|
||||
if (!field.length || field.get(0).selectize) { return; }
|
||||
field.selectize(data);
|
||||
|
||||
this.elements.push(field.data('selectize'));
|
||||
}
|
||||
|
||||
_onAddedNodes(event, target/* , record, instance */) {
|
||||
let fields = $(target).find('select.fancy, input.fancy');
|
||||
if (!fields.length) { return; }
|
||||
|
||||
fields.each((index, field) => this.add(field));
|
||||
}
|
||||
}
|
||||
|
||||
export let Instance = new SelectizeField();
|
||||
104
themes/grav/app/forms/form.js
Normal file
104
themes/grav/app/forms/form.js
Normal file
@@ -0,0 +1,104 @@
|
||||
import $ from 'jquery';
|
||||
import toastr from '../utils/toastr';
|
||||
import { translations } from 'grav-config';
|
||||
import { Instance as FormState } from './state';
|
||||
|
||||
export default class Form {
|
||||
constructor(form) {
|
||||
this.form = $(form);
|
||||
if (!this.form.length || this.form.prop('tagName').toLowerCase() !== 'form') { return; }
|
||||
|
||||
this.form.on('submit', (event) => {
|
||||
if (FormState.equals()) {
|
||||
event.preventDefault();
|
||||
toastr.info(translations.PLUGIN_ADMIN.NOTHING_TO_SAVE);
|
||||
}
|
||||
});
|
||||
|
||||
this._attachShortcuts();
|
||||
this._attachToggleables();
|
||||
this._attachDisabledFields();
|
||||
|
||||
this.observer = new MutationObserver(this.addedNodes);
|
||||
this.form.each((index, form) => this.observer.observe(form, { subtree: true, childList: true }));
|
||||
}
|
||||
|
||||
_attachShortcuts() {
|
||||
// CTRL + S / CMD + S - shortcut for [Save] when available
|
||||
let saveTask = $('[name="task"][value="save"]').filter(function(index, element) {
|
||||
element = $(element);
|
||||
return !(element.parents('.remodal-overlay').length);
|
||||
});
|
||||
|
||||
if (saveTask.length) {
|
||||
$(window).on('keydown', function(event) {
|
||||
var key = String.fromCharCode(event.which).toLowerCase();
|
||||
if ((event.ctrlKey || event.metaKey) && key === 's') {
|
||||
event.preventDefault();
|
||||
saveTask.click();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_attachToggleables() {
|
||||
let query = '[data-grav-field="toggleable"] input[type="checkbox"]';
|
||||
|
||||
this.form.on('change', query, (event) => {
|
||||
let toggle = $(event.target);
|
||||
let enabled = toggle.is(':checked');
|
||||
let parent = toggle.parents('.form-field');
|
||||
let label = parent.find('label.toggleable');
|
||||
let fields = parent.find('.form-data');
|
||||
let inputs = fields.find('input, select, textarea');
|
||||
|
||||
label.add(fields).css('opacity', enabled ? '' : 0.7);
|
||||
inputs.map((index, input) => {
|
||||
let isSelectize = input.selectize;
|
||||
input = $(input);
|
||||
|
||||
if (isSelectize) {
|
||||
isSelectize[enabled ? 'enable' : 'disable']();
|
||||
} else {
|
||||
input.prop('disabled', !enabled);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this.form.find(query).trigger('change');
|
||||
}
|
||||
|
||||
_attachDisabledFields() {
|
||||
let prefix = '.form-field-toggleable .form-data';
|
||||
let query = [];
|
||||
|
||||
['input', 'select', 'label[for]', 'textarea', '.selectize-control'].forEach((item) => {
|
||||
query.push(`${prefix} ${item}`);
|
||||
});
|
||||
|
||||
this.form.on('mousedown', query.join(', '), (event) => {
|
||||
let target = $(event.target);
|
||||
let input = target;
|
||||
let isFor = input.prop('for');
|
||||
let isSelectize = (input.hasClass('selectize-control') || input.parents('.selectize-control')).length;
|
||||
|
||||
if (isFor) { input = $(`[id="${isFor}"]`); }
|
||||
if (isSelectize) { input = input.closest('.selectize-control').siblings('select[name]'); }
|
||||
|
||||
if (!input.prop('disabled')) { return true; }
|
||||
|
||||
let toggle = input.closest('.form-field').find('[data-grav-field="toggleable"] input[type="checkbox"]');
|
||||
toggle.trigger('click');
|
||||
});
|
||||
}
|
||||
|
||||
addedNodes(mutations) {
|
||||
mutations.forEach((mutation) => {
|
||||
if (mutation.type !== 'childList' || !mutation.addedNodes) { return; }
|
||||
|
||||
$('body').trigger('mutation._grav', mutation.target, mutation, this);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export let Instance = new Form('form#blueprints');
|
||||
16
themes/grav/app/forms/index.js
Normal file
16
themes/grav/app/forms/index.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import FormState, { Instance as FormStateInstance } from './state';
|
||||
import Form, { Instance as FormInstance } from './form';
|
||||
|
||||
import Fields from './fields';
|
||||
|
||||
export default {
|
||||
Form: {
|
||||
Form,
|
||||
Instance: FormInstance
|
||||
},
|
||||
Fields,
|
||||
FormState: {
|
||||
FormState,
|
||||
Instance: FormStateInstance
|
||||
}
|
||||
};
|
||||
122
themes/grav/app/forms/state.js
Normal file
122
themes/grav/app/forms/state.js
Normal file
@@ -0,0 +1,122 @@
|
||||
import $ from 'jquery';
|
||||
import Immutable from 'immutable';
|
||||
import '../utils/jquery-utils';
|
||||
|
||||
let FormLoadState = {};
|
||||
|
||||
const DOMBehaviors = {
|
||||
attach() {
|
||||
this.preventUnload();
|
||||
this.preventClickAway();
|
||||
},
|
||||
|
||||
preventUnload() {
|
||||
if ($._data(window, 'events') && ($._data(window, 'events').beforeunload || []).filter((event) => event.namespace === '_grav')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Catch browser uri change / refresh attempt and stop it if the form state is dirty
|
||||
$(window).on('beforeunload._grav', () => {
|
||||
if (Instance.equals() === false) {
|
||||
return `You have made changes on this page that you have not yet confirmed. If you navigate away from this page you will lose your unsaved changes.`;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
preventClickAway() {
|
||||
let selector = 'a[href]:not([href^=#])';
|
||||
|
||||
if ($._data($(selector).get(0), 'events') && ($._data($(selector).get(0), 'events').click || []).filter((event) => event.namespace === '_grav')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent clicking away if the form state is dirty
|
||||
// instead, display a confirmation before continuing
|
||||
$(selector).on('click._grav', function(event) {
|
||||
let isClean = Instance.equals();
|
||||
if (isClean === null || isClean) { return true; }
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
let destination = $(this).attr('href');
|
||||
let modal = $('[data-remodal-id="changes"]');
|
||||
let lookup = $.remodal.lookup[modal.data('remodal')];
|
||||
let buttons = $('a.button', modal);
|
||||
|
||||
let handler = function(event) {
|
||||
event.preventDefault();
|
||||
let action = $(this).data('leave-action');
|
||||
|
||||
buttons.off('click', handler);
|
||||
lookup.close();
|
||||
|
||||
if (action === 'continue') {
|
||||
$(window).off('beforeunload');
|
||||
window.location.href = destination;
|
||||
}
|
||||
};
|
||||
|
||||
buttons.on('click', handler);
|
||||
lookup.open();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default class FormState {
|
||||
constructor(options = {
|
||||
ignore: [],
|
||||
form_id: 'blueprints'
|
||||
}) {
|
||||
this.options = options;
|
||||
this.refresh();
|
||||
|
||||
if (!this.form || !this.fields.length) { return; }
|
||||
FormLoadState = this.collect();
|
||||
DOMBehaviors.attach();
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.form = $(`form#${this.options.form_id}`).filter(':noparents(.remodal)');
|
||||
this.fields = $(`form#${this.options.form_id} *, [form="${this.options.form_id}"]`).filter(':input:not(.no-form)').filter(':noparents(.remodal)');
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
collect() {
|
||||
if (!this.form || !this.fields.length) { return; }
|
||||
|
||||
let values = {};
|
||||
this.refresh().fields.each((index, field) => {
|
||||
field = $(field);
|
||||
let name = field.prop('name');
|
||||
let type = field.prop('type');
|
||||
let value;
|
||||
|
||||
switch (type) {
|
||||
case 'checkbox':
|
||||
case 'radio':
|
||||
value = field.is(':checked');
|
||||
break;
|
||||
default:
|
||||
value = field.val();
|
||||
}
|
||||
|
||||
if (name && !~this.options.ignore.indexOf(name)) {
|
||||
values[name] = value;
|
||||
}
|
||||
});
|
||||
|
||||
return Immutable.OrderedMap(values);
|
||||
}
|
||||
|
||||
// When the form doesn't exist or there are no fields, `equals` returns `null`
|
||||
// for this reason, _NEVER_ check with !Instance.equals(), use Instance.equals() === false
|
||||
equals() {
|
||||
if (!this.form || !this.fields.length) { return null; }
|
||||
return Immutable.is(FormLoadState, this.collect());
|
||||
}
|
||||
};
|
||||
|
||||
export let Instance = new FormState();
|
||||
|
||||
export { DOMBehaviors };
|
||||
29
themes/grav/app/main.js
Normal file
29
themes/grav/app/main.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import GPM, { Instance as gpm } from './utils/gpm';
|
||||
import KeepAlive from './utils/keepalive';
|
||||
import Updates, { Instance as updates } from './updates';
|
||||
import Dashboard from './dashboard';
|
||||
import Pages from './pages';
|
||||
import Forms from './forms';
|
||||
import './plugins';
|
||||
import './themes';
|
||||
|
||||
// bootstrap jQuery extensions
|
||||
import 'bootstrap/js/dropdown';
|
||||
|
||||
// starts the keep alive, auto runs every X seconds
|
||||
KeepAlive.start();
|
||||
|
||||
export default {
|
||||
GPM: {
|
||||
GPM,
|
||||
Instance: gpm
|
||||
},
|
||||
KeepAlive,
|
||||
Dashboard,
|
||||
Pages,
|
||||
Forms,
|
||||
Updates: {
|
||||
Updates,
|
||||
Instance: updates
|
||||
}
|
||||
};
|
||||
134
themes/grav/app/pages/filter.js
Normal file
134
themes/grav/app/pages/filter.js
Normal file
@@ -0,0 +1,134 @@
|
||||
import $ from 'jquery';
|
||||
import { config } from 'grav-config';
|
||||
import request from '../utils/request';
|
||||
import debounce from 'debounce';
|
||||
import { Instance as pagesTree } from './tree';
|
||||
import 'selectize';
|
||||
|
||||
/* @formatter:off */
|
||||
/* eslint-disable */
|
||||
const options = [
|
||||
{ flag: 'Modular', key: 'Modular', cat: 'mode' },
|
||||
{ flag: 'Visible', key: 'Visible', cat: 'mode' },
|
||||
{ flag: 'Routable', key: 'Routable', cat: 'mode' },
|
||||
{ flag: 'Published', key: 'Published', cat: 'mode' },
|
||||
{ flag: 'Non-Modular', key: 'NonModular', cat: 'mode' },
|
||||
{ flag: 'Non-Visible', key: 'NonVisible', cat: 'mode' },
|
||||
{ flag: 'Non-Routable', key: 'NonRoutable', cat: 'mode' },
|
||||
{ flag: 'Non-Published', key: 'NonPublished', cat: 'mode' }
|
||||
];
|
||||
/* @formatter:on */
|
||||
/* eslint-enable */
|
||||
|
||||
export default class PagesFilter {
|
||||
constructor(filters, search) {
|
||||
this.filters = $(filters);
|
||||
this.search = $(search);
|
||||
this.options = options;
|
||||
this.tree = pagesTree;
|
||||
|
||||
if (!this.filters.length || !this.search.length) { return; }
|
||||
|
||||
this.labels = this.filters.data('filter-labels');
|
||||
|
||||
this.search.on('input', debounce(() => this.filter(), 250));
|
||||
this.filters.on('change', () => this.filter());
|
||||
|
||||
this._initSelectize();
|
||||
}
|
||||
|
||||
filter(value) {
|
||||
let data = { flags: '', query: '' };
|
||||
|
||||
if (typeof value === 'object') {
|
||||
Object.assign(data, value);
|
||||
}
|
||||
if (typeof value === 'string') {
|
||||
data.query = value;
|
||||
}
|
||||
if (typeof value === 'undefined') {
|
||||
data.flags = this.filters.val();
|
||||
data.query = this.search.val();
|
||||
}
|
||||
|
||||
if (!Object.keys(data).filter((key) => data[key] !== '').length) {
|
||||
this.resetValues();
|
||||
return;
|
||||
}
|
||||
|
||||
data.flags = data.flags.replace(/(\s{1,})?,(\s{1,})?/g, ',');
|
||||
this.setValues({ flags: data.flags, query: data.query }, 'silent');
|
||||
|
||||
request(`${config.base_url_relative}/pages-filter.json/task${config.param_sep}filterPages`, {
|
||||
method: 'post',
|
||||
body: data
|
||||
}, (response) => {
|
||||
this.refreshDOM(response);
|
||||
});
|
||||
}
|
||||
|
||||
refreshDOM(response) {
|
||||
let items = $('[data-nav-id]');
|
||||
|
||||
if (!response) {
|
||||
items.removeClass('search-match').show();
|
||||
this.tree.restore();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
items.removeClass('search-match').hide();
|
||||
|
||||
response.results.forEach((page) => {
|
||||
let match = items.filter(`[data-nav-id="${page}"]`).addClass('search-match').show();
|
||||
match.parents('[data-nav-id]').addClass('search-match').show();
|
||||
|
||||
this.tree.expand(page, 'no-store');
|
||||
});
|
||||
}
|
||||
|
||||
setValues({ flags = '', query = ''}, silent) {
|
||||
let flagsArray = flags.replace(/(\s{1,})?,(\s{1,})?/g, ',').split(',');
|
||||
if (this.filters.val() !== flags) { this.filters[0].selectize.setValue(flagsArray, silent); }
|
||||
if (this.search.val() !== query) { this.search.val(query); }
|
||||
}
|
||||
|
||||
resetValues() {
|
||||
this.setValues('', 'silent');
|
||||
this.refreshDOM();
|
||||
}
|
||||
|
||||
_initSelectize() {
|
||||
let extras = {
|
||||
type: this.filters.data('filter-types') || {},
|
||||
access: this.filters.data('filter-access-levels') || {}
|
||||
};
|
||||
|
||||
Object.keys(extras).forEach((cat) => {
|
||||
Object.keys(extras[cat]).forEach((key) => {
|
||||
this.options.push({
|
||||
cat,
|
||||
key,
|
||||
flag: extras[cat][key]
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
this.filters.selectize({
|
||||
maxItems: null,
|
||||
valueField: 'key',
|
||||
labelField: 'flag',
|
||||
searchField: ['flag', 'key'],
|
||||
options: this.options,
|
||||
optgroups: this.labels,
|
||||
optgroupField: 'cat',
|
||||
optgroupLabelField: 'name',
|
||||
optgroupValueField: 'id',
|
||||
optgroupOrder: this.labels.map((item) => item.id),
|
||||
plugins: ['optgroup_columns']
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let Instance = new PagesFilter('input[name="page-filter"]', 'input[name="page-search"]');
|
||||
export { Instance };
|
||||
26
themes/grav/app/pages/index.js
Normal file
26
themes/grav/app/pages/index.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import $ from 'jquery';
|
||||
import Sortable from 'sortablejs';
|
||||
import PageFilters, { Instance as PageFiltersInstance } from './filter';
|
||||
import './page';
|
||||
|
||||
// Pages Ordering
|
||||
let Ordering = null;
|
||||
let orderingElement = $('#ordering');
|
||||
if (orderingElement.length) {
|
||||
Ordering = new Sortable(orderingElement.get(0), {
|
||||
filter: '.ignore',
|
||||
onUpdate: function(event) {
|
||||
let item = $(event.item);
|
||||
let index = orderingElement.children().index(item) + 1;
|
||||
$('[data-order]').val(index);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
Ordering,
|
||||
PageFilters: {
|
||||
PageFilters,
|
||||
Instance: PageFiltersInstance
|
||||
}
|
||||
};
|
||||
31
themes/grav/app/pages/page/add.js
Normal file
31
themes/grav/app/pages/page/add.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import $ from 'jquery';
|
||||
|
||||
let custom = false;
|
||||
let folder = $('input[name="folder"]');
|
||||
let title = $('input[name="title"]');
|
||||
|
||||
title.on('input focus blur', () => {
|
||||
if (custom) { return true; }
|
||||
|
||||
let slug = $.slugify(title.val());
|
||||
folder.val(slug);
|
||||
});
|
||||
|
||||
folder.on('input', () => {
|
||||
let input = folder.get(0);
|
||||
let value = folder.val();
|
||||
let selection = {
|
||||
start: input.selectionStart,
|
||||
end: input.selectionEnd
|
||||
};
|
||||
|
||||
value = value.toLowerCase().replace(/\s/g, '-').replace(/[^a-z0-9_\-]/g, '');
|
||||
folder.val(value);
|
||||
custom = !!value;
|
||||
|
||||
// restore cursor position
|
||||
input.setSelectionRange(selection.start, selection.end);
|
||||
|
||||
});
|
||||
|
||||
folder.on('focus blur', () => title.trigger('input'));
|
||||
15
themes/grav/app/pages/page/delete.js
Normal file
15
themes/grav/app/pages/page/delete.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import $ from 'jquery';
|
||||
|
||||
$('[data-remodal-target="delete"]').on('click', function() {
|
||||
let confirm = $('[data-remodal-id="delete"] [data-delete-action]');
|
||||
let link = $(this).data('delete-url');
|
||||
|
||||
confirm.data('delete-action', link);
|
||||
});
|
||||
|
||||
$('[data-delete-action]').on('click', function() {
|
||||
let remodal = $.remodal.lookup[$('[data-remodal-id="delete"]').data('remodal')];
|
||||
|
||||
window.location.href = $(this).data('delete-action');
|
||||
remodal.close();
|
||||
});
|
||||
37
themes/grav/app/pages/page/index.js
Normal file
37
themes/grav/app/pages/page/index.js
Normal file
@@ -0,0 +1,37 @@
|
||||
import $ from 'jquery';
|
||||
import './add';
|
||||
import './move';
|
||||
import './delete';
|
||||
import './media';
|
||||
|
||||
const switcher = $('input[type="radio"][name="mode-switch"]');
|
||||
|
||||
if (switcher) {
|
||||
let link = switcher.closest(':checked').data('leave-url');
|
||||
let fakeLink = $(`<a href="${link}" />`);
|
||||
|
||||
switcher.parent().append(fakeLink);
|
||||
|
||||
switcher.siblings('label').on('mousedown touchdown', (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
// let remodal = $.remodal.lookup[$('[data-remodal-id="changes"]').data('remodal')];
|
||||
let confirm = $('[data-remodal-id="changes"] [data-leave-action="continue"]');
|
||||
|
||||
confirm.one('click', () => {
|
||||
$(window).on('beforeunload._grav');
|
||||
fakeLink.off('click._grav');
|
||||
|
||||
$(event.target).trigger('click');
|
||||
});
|
||||
|
||||
fakeLink.trigger('click._grav');
|
||||
});
|
||||
|
||||
switcher.on('change', (event) => {
|
||||
let radio = $(event.target);
|
||||
link = radio.data('leave-url');
|
||||
|
||||
setTimeout(() => fakeLink.attr('href', link).get(0).click(), 5);
|
||||
});
|
||||
}
|
||||
380
themes/grav/app/pages/page/media.js
Normal file
380
themes/grav/app/pages/page/media.js
Normal file
@@ -0,0 +1,380 @@
|
||||
import $ from 'jquery';
|
||||
import Dropzone from 'dropzone';
|
||||
import request from '../../utils/request';
|
||||
import { config } from 'grav-config';
|
||||
|
||||
Dropzone.autoDiscover = false;
|
||||
Dropzone.options.gravPageDropzone = {};
|
||||
Dropzone.confirm = (question, accepted, rejected) => {
|
||||
let doc = $(document);
|
||||
let modalSelector = '[data-remodal-id="delete-media"]';
|
||||
|
||||
let removeEvents = () => {
|
||||
doc.off('confirm', modalSelector, accept);
|
||||
doc.off('cancel', modalSelector, reject);
|
||||
};
|
||||
|
||||
let accept = () => {
|
||||
accepted && accepted();
|
||||
removeEvents();
|
||||
};
|
||||
|
||||
let reject = () => {
|
||||
rejected && rejected();
|
||||
removeEvents();
|
||||
};
|
||||
|
||||
$.remodal.lookup[$(modalSelector).data('remodal')].open();
|
||||
doc.on('confirmation', modalSelector, accept);
|
||||
doc.on('cancellation', modalSelector, reject);
|
||||
};
|
||||
|
||||
const DropzoneMediaConfig = {
|
||||
createImageThumbnails: { thumbnailWidth: 150 },
|
||||
addRemoveLinks: false,
|
||||
dictRemoveFileConfirmation: '[placeholder]',
|
||||
previewTemplate: `
|
||||
<div class="dz-preview dz-file-preview">
|
||||
<div class="dz-details">
|
||||
<div class="dz-filename"><span data-dz-name></span></div>
|
||||
<div class="dz-size" data-dz-size></div>
|
||||
<img data-dz-thumbnail />
|
||||
</div>
|
||||
<div class="dz-progress"><span class="dz-upload" data-dz-uploadprogress></span></div>
|
||||
<div class="dz-success-mark"><span>✔</span></div>
|
||||
<div class="dz-error-mark"><span>✘</span></div>
|
||||
<div class="dz-error-message"><span data-dz-errormessage></span></div>
|
||||
<a class="dz-remove" href="javascript:undefined;" data-dz-remove>Delete</a>
|
||||
<a class="dz-insert" href="javascript:undefined;" data-dz-insert>Insert</a>
|
||||
</div>`.trim()
|
||||
};
|
||||
|
||||
export default class PageMedia {
|
||||
constructor({form = '[data-media-url]', container = '#grav-dropzone', options = {}} = {}) {
|
||||
this.form = $(form);
|
||||
this.container = $(container);
|
||||
if (!this.form.length || !this.container.length) { return; }
|
||||
|
||||
this.options = Object.assign({}, DropzoneMediaConfig, {
|
||||
url: `${this.form.data('media-url')}/task${config.param_sep}addmedia`,
|
||||
acceptedFiles: this.form.data('media-types')
|
||||
}, options);
|
||||
|
||||
this.dropzone = new Dropzone(container, this.options);
|
||||
this.dropzone.on('complete', this.onDropzoneComplete.bind(this));
|
||||
this.dropzone.on('success', this.onDropzoneSuccess.bind(this));
|
||||
this.dropzone.on('removedfile', this.onDropzoneRemovedFile.bind(this));
|
||||
this.dropzone.on('sending', this.onDropzoneSending.bind(this));
|
||||
|
||||
this.fetchMedia();
|
||||
}
|
||||
|
||||
fetchMedia() {
|
||||
let url = `${this.form.data('media-url')}/task${config.param_sep}listmedia/admin-nonce${config.param_sep}${config.admin_nonce}`;
|
||||
|
||||
request(url, (response) => {
|
||||
let results = response.results;
|
||||
|
||||
Object.keys(results).forEach((name) => {
|
||||
let data = results[name];
|
||||
let mock = { name, size: data.size, accepted: true, extras: data };
|
||||
|
||||
this.dropzone.files.push(mock);
|
||||
this.dropzone.options.addedfile.call(this.dropzone, mock);
|
||||
|
||||
if (name.match(/\.(jpg|jpeg|png|gif)$/i)) {
|
||||
this.dropzone.options.thumbnail.call(this.dropzone, mock, data.url);
|
||||
}
|
||||
});
|
||||
|
||||
this.container.find('.dz-preview').prop('draggable', 'true');
|
||||
});
|
||||
}
|
||||
|
||||
onDropzoneSending(file, xhr, formData) {
|
||||
formData.append('admin-nonce', config.admin_nonce);
|
||||
}
|
||||
|
||||
onDropzoneSuccess(file, response, xhr) {
|
||||
return this.handleError({
|
||||
file,
|
||||
data: response,
|
||||
mode: 'removeFile',
|
||||
msg: `<p>An error occurred while trying to upload the file <strong>${file.name}</strong></p>
|
||||
<pre>${response.message}</pre>`
|
||||
});
|
||||
}
|
||||
|
||||
onDropzoneComplete(file) {
|
||||
if (!file.accepted) {
|
||||
let data = {
|
||||
status: 'error',
|
||||
message: `Unsupported file type: ${file.name.match(/\..+/).join('')}`
|
||||
};
|
||||
|
||||
return this.handleError({
|
||||
file,
|
||||
data,
|
||||
mode: 'removeFile',
|
||||
msg: `<p>An error occurred while trying to add the file <strong>${file.name}</strong></p>
|
||||
<pre>${data.message}</pre>`
|
||||
});
|
||||
}
|
||||
|
||||
// accepted
|
||||
$('.dz-preview').prop('draggable', 'true');
|
||||
}
|
||||
|
||||
onDropzoneRemovedFile(file, ...extra) {
|
||||
if (!file.accepted || file.rejected) { return; }
|
||||
let url = `${this.form.data('media-url')}/task${config.param_sep}delmedia`;
|
||||
|
||||
request(url, {
|
||||
method: 'post',
|
||||
body: {
|
||||
filename: file.name
|
||||
}
|
||||
}, (response) => {
|
||||
return this.handleError({
|
||||
file,
|
||||
data: response,
|
||||
mode: 'addBack',
|
||||
msg: `<p>An error occurred while trying to remove the file <strong>${file.name}</strong></p>
|
||||
<pre>${response.message}</pre>`
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
handleError(options) {
|
||||
let { file, data, mode, msg } = options;
|
||||
if (data.status !== 'error' && data.status !== 'unauthorized') { return ; }
|
||||
|
||||
switch (mode) {
|
||||
case 'addBack':
|
||||
if (file instanceof File) {
|
||||
this.dropzone.addFile(file);
|
||||
} else {
|
||||
this.dropzone.files.push(file);
|
||||
this.dropzone.options.addedfile.call(this, file);
|
||||
this.dropzone.options.thumbnail.call(this, file, file.extras.url);
|
||||
}
|
||||
|
||||
break;
|
||||
case 'removeFile':
|
||||
file.rejected = true;
|
||||
this.dropzone.removeFile(file);
|
||||
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
let modal = $('[data-remodal-id="generic"]');
|
||||
modal.find('.error-content').html(msg);
|
||||
$.remodal.lookup[modal.data('remodal')].open();
|
||||
}
|
||||
}
|
||||
|
||||
export let Instance = new PageMedia();
|
||||
|
||||
// let container = $('[data-media-url]');
|
||||
|
||||
// if (container.length) {
|
||||
/* let URI = container.data('media-url');
|
||||
let dropzone = new Dropzone('#grav-dropzone', {
|
||||
url: `${URI}/task${config.param_sep}addmedia`,
|
||||
createImageThumbnails: { thumbnailWidth: 150 },
|
||||
addRemoveLinks: false,
|
||||
dictRemoveFileConfirmation: '[placeholder]',
|
||||
acceptedFiles: container.data('media-types'),
|
||||
previewTemplate: `
|
||||
<div class="dz-preview dz-file-preview">
|
||||
<div class="dz-details">
|
||||
<div class="dz-filename"><span data-dz-name></span></div>
|
||||
<div class="dz-size" data-dz-size></div>
|
||||
<img data-dz-thumbnail />
|
||||
</div>
|
||||
<div class="dz-progress"><span class="dz-upload" data-dz-uploadprogress></span></div>
|
||||
<div class="dz-success-mark"><span>✔</span></div>
|
||||
<div class="dz-error-mark"><span>✘</span></div>
|
||||
<div class="dz-error-message"><span data-dz-errormessage></span></div>
|
||||
<a class="dz-remove" href="javascript:undefined;" data-dz-remove>Delete</a>
|
||||
<a class="dz-insert" href="javascript:undefined;" data-dz-insert>Insert</a>
|
||||
</div>`
|
||||
});*/
|
||||
|
||||
/* $.get(URI + '/task{{ config.system.param_sep }}listmedia/admin-nonce{{ config.system.param_sep }}' + GravAdmin.config.admin_nonce, function(data) {
|
||||
|
||||
$.proxy(modalError, this, {
|
||||
data: data,
|
||||
msg: '<p>An error occurred while trying to list files</p><pre>'+data.message+'</pre>'
|
||||
})();
|
||||
|
||||
if (data.results) {
|
||||
$.each(data.results, function(filename, data){
|
||||
var mockFile = { name: filename, size: data.size, accepted: true, extras: data };
|
||||
thisDropzone.files.push(mockFile);
|
||||
thisDropzone.options.addedfile.call(thisDropzone, mockFile);
|
||||
|
||||
if (filename.toLowerCase().match(/\.(jpg|jpeg|png|gif)$/)) {
|
||||
thisDropzone.options.thumbnail.call(thisDropzone, mockFile, data.url);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$('.dz-preview').prop('draggable', 'true');
|
||||
});*/
|
||||
|
||||
// console.log(dropzone);
|
||||
// }
|
||||
|
||||
/*
|
||||
<script>
|
||||
$(function(){
|
||||
var URI = $('[data-media-url]').data('media-url'), thisDropzone,
|
||||
modalError = function(args){
|
||||
if (args.data.status == 'error' || args.data.status == 'unauthorized'){
|
||||
|
||||
if (args.mode == 'addBack'){
|
||||
// let's add back the file
|
||||
if (args.file instanceof File) this.addFile(args.file);
|
||||
else {
|
||||
this.files.push(args.file);
|
||||
this.options.addedfile.call(this, args.file);
|
||||
this.options.thumbnail.call(this, args.file, args.file.extras.url);
|
||||
}
|
||||
} else if (args.mode == 'removeFile') {
|
||||
args.file.rejected = true;
|
||||
this.removeFile(args.file);
|
||||
}
|
||||
|
||||
// fire up the modal
|
||||
var modalContainer = $('[data-remodal-id=generic]');
|
||||
modalContainer.find('.error-content').html(args.msg);
|
||||
$.remodal.lookup[modalContainer.data('remodal')].open();
|
||||
}
|
||||
};
|
||||
Dropzone.autoDiscover = false;
|
||||
Dropzone.confirm = function(question, accepted, rejected) {
|
||||
var modalContainer = $('[data-remodal-id=delete-media]'),
|
||||
acceptHandler = function () {
|
||||
if (accepted) {
|
||||
accepted();
|
||||
}
|
||||
$(document).off('confirm', '[data-remodal-id=delete-media]', acceptHandler);
|
||||
$(document).off('cancel', '[data-remodal-id=delete-media]', rejectHandler);
|
||||
},
|
||||
rejectHandler = function () {
|
||||
if (rejected) {
|
||||
rejected();
|
||||
}
|
||||
$(document).off('confirm', '[data-remodal-id=delete-media]', acceptHandler);
|
||||
$(document).off('cancel', '[data-remodal-id=delete-media]', rejectHandler);
|
||||
};
|
||||
|
||||
$.remodal.lookup[modalContainer.data('remodal')].open();
|
||||
$(document).on('confirm', '[data-remodal-id=delete-media]', acceptHandler);
|
||||
$(document).on('cancel', '[data-remodal-id=delete-media]', rejectHandler);
|
||||
};
|
||||
Dropzone.options.gravDropzone = {
|
||||
addRemoveLinks: false,
|
||||
dictRemoveFileConfirmation: '[placeholder]',
|
||||
acceptedFiles: $('[data-media-types]').data('media-types'),
|
||||
previewTemplate: "<div class=\"dz-preview dz-file-preview\">\n <div class=\"dz-details\">\n " +
|
||||
"<div class=\"dz-filename\"><span data-dz-name></span></div>\n " +
|
||||
"<div class=\"dz-size\" data-dz-size></div>\n <img data-dz-thumbnail />\n </div>\n " +
|
||||
"<div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress></span></div>\n "+
|
||||
"<div class=\"dz-success-mark\"><span>✔</span></div>\n <div class=\"dz-error-mark\"><span>✘</span></div>\n " +
|
||||
"<div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n" +
|
||||
"<a class=\"dz-remove\" href=\"javascript:undefined;\" data-dz-remove>Delete</a>\n" +
|
||||
"<a class=\"dz-insert\" href=\"javascript:undefined;\" data-dz-insert>Insert</a>\n</div>",
|
||||
init: function() {
|
||||
thisDropzone = this;
|
||||
$.get(URI + '/task{{ config.system.param_sep }}listmedia/admin-nonce{{ config.system.param_sep }}' + GravAdmin.config.admin_nonce, function(data) {
|
||||
|
||||
$.proxy(modalError, this, {
|
||||
data: data,
|
||||
msg: '<p>An error occurred while trying to list files</p><pre>'+data.message+'</pre>'
|
||||
})();
|
||||
|
||||
if (data.results) {
|
||||
$.each(data.results, function(filename, data){
|
||||
var mockFile = { name: filename, size: data.size, accepted: true, extras: data };
|
||||
thisDropzone.files.push(mockFile);
|
||||
thisDropzone.options.addedfile.call(thisDropzone, mockFile);
|
||||
|
||||
if (filename.toLowerCase().match(/\.(jpg|jpeg|png|gif)$/)) {
|
||||
thisDropzone.options.thumbnail.call(thisDropzone, mockFile, data.url);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$('.dz-preview').prop('draggable', 'true');
|
||||
});
|
||||
|
||||
this.on("complete", function(file) {
|
||||
if (file.accepted) {
|
||||
$('.dz-preview').prop('draggable', 'true');
|
||||
return;
|
||||
}
|
||||
var data = {status: 'error', message: 'Unsupported file type: ' + file.name.match(/\..+/).join('')};
|
||||
$.proxy(modalError, this, {
|
||||
file: file,
|
||||
data: data,
|
||||
mode: 'removeFile',
|
||||
msg: '<p>An error occurred while trying to add the file <strong>'+file.name+'</strong></p><pre>'+data.message+'</pre>'
|
||||
})();
|
||||
});
|
||||
|
||||
this.on('success', function(file, response){
|
||||
thisDropzone = this;
|
||||
$.proxy(modalError, this, {
|
||||
file: file,
|
||||
data: response,
|
||||
mode: 'removeFile',
|
||||
msg: '<p>An error occurred while trying to upload the file <strong>'+file.name+'</strong></p><pre>'+response.message+'</pre>'
|
||||
})();
|
||||
});
|
||||
|
||||
this.on('removedfile', function(file) {
|
||||
if (!file.accepted || file.rejected) return;
|
||||
thisDropzone = this;
|
||||
$.post(URI + '/task{{ config.system.param_sep }}delmedia', {filename: file.name, 'admin-nonce': GravAdmin.config.admin_nonce}, function(data){
|
||||
$.proxy(modalError, thisDropzone, {
|
||||
file: file,
|
||||
data: data,
|
||||
mode: 'addBack',
|
||||
msg: '<p>An error occurred while trying to remove the file <strong>'+file.name+'</strong></p><pre>'+data.message+'</pre>'
|
||||
})();
|
||||
});
|
||||
});
|
||||
|
||||
this.on('sending', function(file, xhr, formData){
|
||||
formData.append('admin-nonce', GravAdmin.config.admin_nonce);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var dropzone = new Dropzone("#gravDropzone", { url: URI + '/task{{ config.system.param_sep }}addmedia', createImageThumbnails: { thumbnailWidth: 150} });
|
||||
|
||||
$("#gravDropzone").delegate('.dz-preview', 'dragstart', function(e){
|
||||
var uri = encodeURI($(this).find('.dz-filename').text());
|
||||
uri = uri.replace(/\(/g, '%28');
|
||||
uri = uri.replace(/\)/g, '%29');
|
||||
|
||||
var shortcode = '';
|
||||
if (!uri.match(/\.(jpg|jpeg|png|gif)$/)) {
|
||||
shortcode = '[' + decodeURI(uri) + '](' + uri + ')';
|
||||
}
|
||||
|
||||
dropzone.disable();
|
||||
$(this).addClass('hide-backface');
|
||||
e.originalEvent.dataTransfer.effectAllowed = 'copy';
|
||||
e.originalEvent.dataTransfer.setData('text', shortcode);
|
||||
});
|
||||
|
||||
$("#gravDropzone").delegate('.dz-preview', 'dragend', function(e){
|
||||
dropzone.enable();
|
||||
$(this).removeClass('hide-backface');
|
||||
});
|
||||
});
|
||||
</script>*/
|
||||
13
themes/grav/app/pages/page/move.js
Normal file
13
themes/grav/app/pages/page/move.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import $ from 'jquery';
|
||||
|
||||
$('[data-page-move] button[name="task"][value="save"]').on('click', function() {
|
||||
let route = $('form#blueprints:first select[name="route"]');
|
||||
let moveTo = $('[data-page-move] select').val();
|
||||
|
||||
if (route.length && route.val() !== moveTo) {
|
||||
let selectize = route.data('selectize');
|
||||
route.val(moveTo);
|
||||
|
||||
if (selectize) selectize.setValue(moveTo);
|
||||
}
|
||||
});
|
||||
116
themes/grav/app/pages/tree.js
Normal file
116
themes/grav/app/pages/tree.js
Normal file
@@ -0,0 +1,116 @@
|
||||
import $ from 'jquery';
|
||||
|
||||
const sessionKey = 'grav:admin:pages';
|
||||
|
||||
if (!sessionStorage.getItem(sessionKey)) {
|
||||
sessionStorage.setItem(sessionKey, '{}');
|
||||
}
|
||||
|
||||
export default class PagesTree {
|
||||
constructor(elements) {
|
||||
this.elements = $(elements);
|
||||
this.session = JSON.parse(sessionStorage.getItem(sessionKey));
|
||||
|
||||
if (!this.elements.length) { return; }
|
||||
|
||||
this.restore();
|
||||
|
||||
this.elements.find('.page-icon').on('click', (event) => this.toggle(event.target));
|
||||
|
||||
$('[data-page-toggleall]').on('click', (event) => {
|
||||
let element = $(event.target).closest('[data-page-toggleall]');
|
||||
let action = element.data('page-toggleall');
|
||||
|
||||
this[action]();
|
||||
});
|
||||
}
|
||||
|
||||
toggle(elements, dontStore = false) {
|
||||
if (typeof elements === 'string') {
|
||||
elements = $(`[data-nav-id="${elements}"]`).find('[data-toggle="children"]');
|
||||
}
|
||||
|
||||
elements = $(elements || this.elements);
|
||||
elements.each((index, element) => {
|
||||
element = $(element);
|
||||
let state = this.getState(element.closest('[data-toggle="children"]'));
|
||||
this[state.isOpen ? 'collapse' : 'expand'](state.id, dontStore);
|
||||
});
|
||||
}
|
||||
|
||||
collapse(elements, dontStore = false) {
|
||||
if (typeof elements === 'string') {
|
||||
elements = $(`[data-nav-id="${elements}"]`).find('[data-toggle="children"]');
|
||||
}
|
||||
|
||||
elements = $(elements || this.elements);
|
||||
elements.each((index, element) => {
|
||||
element = $(element);
|
||||
let state = this.getState(element);
|
||||
|
||||
if (state.isOpen) {
|
||||
state.children.hide();
|
||||
state.icon.removeClass('children-open').addClass('children-closed');
|
||||
if (!dontStore) { delete this.session[state.id]; }
|
||||
}
|
||||
});
|
||||
|
||||
if (!dontStore) { this.save(); }
|
||||
}
|
||||
|
||||
expand(elements, dontStore = false) {
|
||||
if (typeof elements === 'string') {
|
||||
let element = $(`[data-nav-id="${elements}"]`);
|
||||
let parents = element.parents('[data-nav-id]');
|
||||
|
||||
// loop back through parents, we don't want to expand an hidden child
|
||||
if (parents.length) {
|
||||
parents = parents.find('[data-toggle="children"]:first');
|
||||
parents = parents.add(element.find('[data-toggle="children"]:first'));
|
||||
return this.expand(parents, dontStore);
|
||||
}
|
||||
|
||||
elements = element.find('[data-toggle="children"]:first');
|
||||
}
|
||||
|
||||
elements = $(elements || this.elements);
|
||||
elements.each((index, element) => {
|
||||
element = $(element);
|
||||
let state = this.getState(element);
|
||||
|
||||
if (!state.isOpen) {
|
||||
state.children.show();
|
||||
state.icon.removeClass('children-closed').addClass('children-open');
|
||||
if (!dontStore) { this.session[state.id] = 1; }
|
||||
}
|
||||
});
|
||||
|
||||
if (!dontStore) { this.save(); }
|
||||
}
|
||||
|
||||
restore() {
|
||||
this.collapse(null, true);
|
||||
|
||||
Object.keys(this.session).forEach((key) => {
|
||||
this.expand(key, 'no-store');
|
||||
});
|
||||
}
|
||||
|
||||
save() {
|
||||
return sessionStorage.setItem(sessionKey, JSON.stringify(this.session));
|
||||
}
|
||||
|
||||
getState(element) {
|
||||
element = $(element);
|
||||
|
||||
return {
|
||||
id: element.closest('[data-nav-id]').data('nav-id'),
|
||||
children: element.closest('li.page-item').find('ul:first'),
|
||||
icon: element.find('.page-icon'),
|
||||
get isOpen() { return this.icon.hasClass('children-open'); }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
let Instance = new PagesTree('[data-toggle="children"]');
|
||||
export { Instance };
|
||||
24
themes/grav/app/plugins/index.js
Normal file
24
themes/grav/app/plugins/index.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import $ from 'jquery';
|
||||
|
||||
// Plugins sliders details
|
||||
$('.gpm-name, .gpm-actions').on('click', function(e) {
|
||||
let element = $(this);
|
||||
let target = $(e.target);
|
||||
let tag = target.prop('tagName').toLowerCase();
|
||||
|
||||
if (tag === 'a' || element.parent('a').length) { return true; }
|
||||
|
||||
let wrapper = element.siblings('.gpm-details').find('.table-wrapper');
|
||||
|
||||
wrapper.slideToggle({
|
||||
duration: 350,
|
||||
complete: () => {
|
||||
let visible = wrapper.is(':visible');
|
||||
wrapper
|
||||
.closest('tr')
|
||||
.find('.gpm-details-expand i')
|
||||
.removeClass('fa-chevron-' + (visible ? 'down' : 'up'))
|
||||
.addClass('fa-chevron-' + (visible ? 'up' : 'down'));
|
||||
}
|
||||
});
|
||||
});
|
||||
10
themes/grav/app/themes/index.js
Normal file
10
themes/grav/app/themes/index.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import $ from 'jquery';
|
||||
|
||||
// Themes Switcher Warning
|
||||
$(document).on('mousedown', '[data-remodal-target="theme-switch-warn"]', (event) => {
|
||||
let name = $(event.target).closest('[data-gpm-theme]').find('.gpm-name a:first').text();
|
||||
let remodal = $('.remodal.theme-switcher');
|
||||
|
||||
remodal.find('strong').text(name);
|
||||
remodal.find('.button.continue').attr('href', $(event.target).attr('href'));
|
||||
});
|
||||
26
themes/grav/app/updates/check.js
Normal file
26
themes/grav/app/updates/check.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import $ from 'jquery';
|
||||
import { Instance as gpm } from '../utils/gpm';
|
||||
import { translations } from 'grav-config';
|
||||
import toastr from '../utils/toastr';
|
||||
|
||||
// Check for updates trigger
|
||||
$('[data-gpm-checkupdates]').on('click', function() {
|
||||
let element = $(this);
|
||||
element.find('i').addClass('fa-spin');
|
||||
|
||||
gpm.fetch((response) => {
|
||||
element.find('i').removeClass('fa-spin');
|
||||
let payload = response.payload;
|
||||
|
||||
if (!payload) { return; }
|
||||
if (!payload.grav.isUpdatable && !payload.resources.total) {
|
||||
toastr.success(translations.PLUGIN_ADMIN.EVERYTHING_UP_TO_DATE);
|
||||
} else {
|
||||
var grav = payload.grav.isUpdatable ? 'Grav v' + payload.grav.available : '';
|
||||
var resources = payload.resources.total ? payload.resources.total + ' ' + translations.PLUGIN_ADMIN.UPDATES_ARE_AVAILABLE : '';
|
||||
|
||||
if (!resources) { grav += ' ' + translations.PLUGIN_ADMIN.IS_AVAILABLE_FOR_UPDATE; }
|
||||
toastr.info(grav + (grav && resources ? ' ' + translations.PLUGIN_ADMIN.AND + ' ' : '') + resources);
|
||||
}
|
||||
}, true);
|
||||
});
|
||||
134
themes/grav/app/updates/index.js
Normal file
134
themes/grav/app/updates/index.js
Normal file
@@ -0,0 +1,134 @@
|
||||
import $ from 'jquery';
|
||||
import { config, translations } from 'grav-config';
|
||||
import formatBytes from '../utils/formatbytes';
|
||||
import { Instance as gpm } from '../utils/gpm';
|
||||
import './check';
|
||||
import './update';
|
||||
|
||||
export default class Updates {
|
||||
constructor(payload = {}) {
|
||||
this.setPayload(payload);
|
||||
this.task = `task${config.param_sep}`;
|
||||
}
|
||||
|
||||
setPayload(payload = {}) {
|
||||
this.payload = payload;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
fetch(force = false) {
|
||||
gpm.fetch((response) => this.setPayload(response), force);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
maintenance(mode = 'hide') {
|
||||
let element = $('#updates [data-maintenance-update]');
|
||||
|
||||
element[mode === 'show' ? 'fadeIn' : 'fadeOut']();
|
||||
|
||||
if (mode === 'hide') {
|
||||
$('.badges.with-updates').removeClass('with-updates').find('.badge.updates').remove();
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
grav() {
|
||||
let payload = this.payload.grav;
|
||||
|
||||
if (payload.isUpdatable) {
|
||||
let task = this.task;
|
||||
let bar = `
|
||||
<i class="fa fa-bullhorn"></i>
|
||||
Grav <b>v${payload.available}</b> ${translations.PLUGIN_ADMIN.IS_NOW_AVAILABLE}! <span class="less">(${translations.PLUGIN_ADMIN.CURRENT}v${payload.version})</span>
|
||||
`;
|
||||
|
||||
if (!payload.isSymlink) {
|
||||
bar += `<button data-maintenance-update="${config.base_url_relative}/update.json/${task}updategrav/admin-nonce${config.param_sep}${config.admin_nonce}" class="button button-small secondary" id="grav-update-button">${translations.PLUGIN_ADMIN.UPDATE_GRAV_NOW}</button>`;
|
||||
} else {
|
||||
bar += `<span class="hint--left" style="float: right;" data-hint="${translations.PLUGIN_ADMIN.GRAV_SYMBOLICALLY_LINKED}"><i class="fa fa-fw fa-link"></i></span>`;
|
||||
}
|
||||
|
||||
$('[data-gpm-grav]').addClass('grav').html(`<p>${bar}</p>`);
|
||||
}
|
||||
|
||||
$('#grav-update-button').on('click', function() {
|
||||
$(this).html(`${translations.PLUGIN_ADMIN.UPDATING_PLEASE_WAIT} ${formatBytes(payload.assets['grav-update'].size)}..`);
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
resources() {
|
||||
if (!this.payload.resources.total) { return this.maintenance('hide'); }
|
||||
|
||||
let map = ['plugins', 'themes'];
|
||||
let singles = ['plugin', 'theme'];
|
||||
let task = this.task;
|
||||
let { plugins, themes } = this.payload.resources;
|
||||
|
||||
if (!this.payload.resources.total) { return this; }
|
||||
|
||||
[plugins, themes].forEach(function(resources, index) {
|
||||
if (!resources || Array.isArray(resources)) { return; }
|
||||
let length = Object.keys(resources).length;
|
||||
let type = map[index];
|
||||
|
||||
// sidebar
|
||||
$(`#admin-menu a[href$="/${map[index]}"]`)
|
||||
.find('.badges')
|
||||
.addClass('with-updates')
|
||||
.find('.badge.updates').text(length);
|
||||
|
||||
// update all
|
||||
let title = type.charAt(0).toUpperCase() + type.substr(1).toLowerCase();
|
||||
let updateAll = $(`.grav-update.${type}`);
|
||||
updateAll.html(`
|
||||
<p>
|
||||
<i class="fa fa-bullhorn"></i>
|
||||
${length} ${translations.PLUGIN_ADMIN.OF_YOUR} ${type} ${translations.PLUGIN_ADMIN.HAVE_AN_UPDATE_AVAILABLE}
|
||||
<a href="${config.base_url_relative}/${type}/${task}update/admin-nonce${config.param_sep}${config.admin_nonce}" class="button button-small secondary">${translations.PLUGIN_ADMIN.UPDATE} All ${title}</a>
|
||||
</p>
|
||||
`);
|
||||
|
||||
Object.keys(resources).forEach(function(item) {
|
||||
// listing page
|
||||
let element = $(`[data-gpm-${singles[index]}="${item}"] .gpm-name`);
|
||||
let url = element.find('a');
|
||||
|
||||
if (type === 'plugins' && !element.find('.badge.update').length) {
|
||||
element.append(`<a class="plugin-update-button" href="${url.attr('href')}"><span class="badge update">${translations.PLUGIN_ADMIN.UPDATE_AVAILABLE}!</span></a>`);
|
||||
} else if (type === 'themes') {
|
||||
element.append(`<div class="gpm-ribbon"><a href="${url.attr('href')}">${translations.PLUGIN_ADMIN.UPDATE.toUpperCase()}</a></div>`);
|
||||
}
|
||||
|
||||
// details page
|
||||
let details = $(`.grav-update.${singles[index]}`);
|
||||
if (details.length) {
|
||||
details.html(`
|
||||
<p>
|
||||
<i class="fa fa-bullhorn"></i>
|
||||
<strong>v${resources[item].available}</strong> ${translations.PLUGIN_ADMIN.OF_THIS} ${singles[index]} ${translations.PLUGIN_ADMIN.IS_NOW_AVAILABLE}!
|
||||
<a href="${config.base_url_relative}/${type}/${item}/${task}update/admin-nonce${config.param_sep}${config.admin_nonce}" class="button button-small secondary">${translations.PLUGIN_ADMIN.UPDATE} ${singles[index].charAt(0).toUpperCase() + singles[index].substr(1).toLowerCase()}</a>
|
||||
</p>
|
||||
`);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let Instance = new Updates();
|
||||
export { Instance };
|
||||
|
||||
// automatically refresh UI for updates (graph, sidebar, plugin/themes pages) after every fetch
|
||||
gpm.on('fetched', (response, raw) => {
|
||||
Instance.setPayload(response.payload || {});
|
||||
Instance.grav().resources();
|
||||
});
|
||||
|
||||
if (config.enable_auto_updates_check === '1') {
|
||||
gpm.fetch();
|
||||
}
|
||||
19
themes/grav/app/updates/update.js
Normal file
19
themes/grav/app/updates/update.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import $ from 'jquery';
|
||||
import request from '../utils/request';
|
||||
|
||||
// Dashboard update and Grav update
|
||||
$('body').on('click', '[data-maintenance-update]', function() {
|
||||
let element = $(this);
|
||||
let url = element.data('maintenanceUpdate');
|
||||
|
||||
element.attr('disabled', 'disabled').find('> .fa').removeClass('fa-cloud-download').addClass('fa-refresh fa-spin');
|
||||
|
||||
request(url, (response) => {
|
||||
if (response.type === 'updategrav') {
|
||||
$('[data-gpm-grav]').remove();
|
||||
$('#footer .grav-version').html(response.version);
|
||||
}
|
||||
|
||||
element.removeAttr('disabled').find('> .fa').removeClass('fa-refresh fa-spin').addClass('fa-cloud-download');
|
||||
});
|
||||
});
|
||||
11
themes/grav/app/utils/formatbytes.js
Normal file
11
themes/grav/app/utils/formatbytes.js
Normal file
@@ -0,0 +1,11 @@
|
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
|
||||
export default function formatBytes(bytes, decimals) {
|
||||
if (bytes === 0) return '0 Byte';
|
||||
|
||||
let k = 1000;
|
||||
let value = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
let decimal = decimals + 1 || 3;
|
||||
|
||||
return (bytes / Math.pow(k, value)).toPrecision(decimal) + ' ' + sizes[value];
|
||||
}
|
||||
58
themes/grav/app/utils/gpm.js
Normal file
58
themes/grav/app/utils/gpm.js
Normal file
@@ -0,0 +1,58 @@
|
||||
import { parseJSON, parseStatus, userFeedbackError } from './response';
|
||||
import { config } from 'grav-config';
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
export default class GPM extends EventEmitter {
|
||||
constructor(action = 'getUpdates') {
|
||||
super();
|
||||
this.payload = {};
|
||||
this.raw = {};
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
setPayload(payload = {}) {
|
||||
this.payload = payload;
|
||||
this.emit('payload', payload);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
setAction(action = 'getUpdates') {
|
||||
this.action = action;
|
||||
this.emit('action', action);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
fetch(callback = () => true, flush = false) {
|
||||
let data = new FormData();
|
||||
data.append('task', 'GPM');
|
||||
data.append('action', this.action);
|
||||
|
||||
if (flush) {
|
||||
data.append('flush', true);
|
||||
}
|
||||
|
||||
this.emit('fetching', this);
|
||||
|
||||
fetch(config.base_url_relative, {
|
||||
credentials: 'same-origin',
|
||||
method: 'post',
|
||||
body: data
|
||||
}).then((response) => { this.raw = response; return response; })
|
||||
.then(parseStatus)
|
||||
.then(parseJSON)
|
||||
.then((response) => this.response(response))
|
||||
.then((response) => callback(response, this.raw))
|
||||
.then((response) => this.emit('fetched', this.payload, this.raw, this))
|
||||
.catch(userFeedbackError);
|
||||
}
|
||||
|
||||
response(response) {
|
||||
this.payload = response;
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
export let Instance = new GPM();
|
||||
4
themes/grav/app/utils/jquery-utils.js
vendored
Normal file
4
themes/grav/app/utils/jquery-utils.js
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import $ from 'jquery';
|
||||
|
||||
// jQuery no parents filter
|
||||
$.expr[':']['noparents'] = $.expr.createPseudo((text) => (element) => $(element).parents(text).length < 1);
|
||||
32
themes/grav/app/utils/keepalive.js
Normal file
32
themes/grav/app/utils/keepalive.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import { config } from 'grav-config';
|
||||
import { userFeedbackError } from './response';
|
||||
|
||||
class KeepAlive {
|
||||
constructor() {
|
||||
this.active = false;
|
||||
}
|
||||
|
||||
start() {
|
||||
let timeout = config.admin_timeout / 1.5 * 1000;
|
||||
this.timer = setInterval(() => this.fetch(), timeout);
|
||||
this.active = true;
|
||||
}
|
||||
|
||||
stop() {
|
||||
clearInterval(this.timer);
|
||||
this.active = false;
|
||||
}
|
||||
|
||||
fetch() {
|
||||
let data = new FormData();
|
||||
data.append('admin-nonce', config.admin_nonce);
|
||||
|
||||
fetch(`${config.base_url_relative}/task${config.param_sep}keepAlive`, {
|
||||
credentials: 'same-origin',
|
||||
method: 'post',
|
||||
body: data
|
||||
}).catch(userFeedbackError);
|
||||
}
|
||||
}
|
||||
|
||||
export default new KeepAlive();
|
||||
38
themes/grav/app/utils/request.js
Normal file
38
themes/grav/app/utils/request.js
Normal file
@@ -0,0 +1,38 @@
|
||||
import { parseStatus, parseJSON, userFeedback, userFeedbackError } from './response';
|
||||
import { config } from 'grav-config';
|
||||
|
||||
let raw;
|
||||
let request = function(url, options = {}, callback = () => true) {
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
if (options.method && options.method === 'post' && options.body) {
|
||||
let data = new FormData();
|
||||
|
||||
options.body = Object.assign({ 'admin-nonce': config.admin_nonce }, options.body);
|
||||
Object.keys(options.body).map((key) => data.append(key, options.body[key]));
|
||||
options.body = data;
|
||||
}
|
||||
|
||||
options = Object.assign({
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
}, options);
|
||||
|
||||
return fetch(url, options)
|
||||
.then((response) => {
|
||||
raw = response;
|
||||
return response;
|
||||
})
|
||||
.then(parseStatus)
|
||||
.then(parseJSON)
|
||||
.then(userFeedback)
|
||||
.then((response) => callback(response, raw))
|
||||
.catch(userFeedbackError);
|
||||
};
|
||||
|
||||
export default request;
|
||||
68
themes/grav/app/utils/response.js
Normal file
68
themes/grav/app/utils/response.js
Normal file
@@ -0,0 +1,68 @@
|
||||
import toastr from './toastr';
|
||||
import { config } from 'grav-config';
|
||||
|
||||
let error = function(response) {
|
||||
let error = new Error(response.statusText || response || '');
|
||||
error.response = response;
|
||||
|
||||
return error;
|
||||
};
|
||||
|
||||
export function parseStatus(response) {
|
||||
if (response.status >= 200 && response.status < 300) {
|
||||
return response;
|
||||
} else {
|
||||
throw error(response);
|
||||
}
|
||||
}
|
||||
|
||||
export function parseJSON(response) {
|
||||
return response.json();
|
||||
}
|
||||
|
||||
export function userFeedback(response) {
|
||||
let status = response.status;
|
||||
let message = response.message || null;
|
||||
let settings = response.toastr || null;
|
||||
let backup;
|
||||
|
||||
switch (status) {
|
||||
case 'unauthenticated':
|
||||
document.location.href = config.base_url_relative;
|
||||
throw error('Logged out');
|
||||
case 'unauthorized':
|
||||
status = 'error';
|
||||
message = message || 'Unauthorized.';
|
||||
break;
|
||||
case 'error':
|
||||
status = 'error';
|
||||
message = message || 'Unknown error.';
|
||||
break;
|
||||
case 'success':
|
||||
status = 'success';
|
||||
message = message || '';
|
||||
break;
|
||||
default:
|
||||
status = 'error';
|
||||
message = message || 'Invalid AJAX response.';
|
||||
break;
|
||||
}
|
||||
|
||||
if (settings) {
|
||||
backup = Object.assign({}, toastr.options);
|
||||
Object.keys(settings).forEach((key) => toastr.options[key] = settings[key]);
|
||||
}
|
||||
|
||||
if (message) { toastr[status === 'success' ? 'success' : 'error'](message); }
|
||||
|
||||
if (settings) {
|
||||
toastr.options = backup;
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
export function userFeedbackError(error) {
|
||||
toastr.error(`Fetch Failed: <br /> ${error.message} <pre><code>${error.stack}</code></pre>`);
|
||||
console.error(`${error.message} at ${error.stack}`);
|
||||
}
|
||||
6
themes/grav/app/utils/toastr.js
Normal file
6
themes/grav/app/utils/toastr.js
Normal file
@@ -0,0 +1,6 @@
|
||||
import toastr from 'toastr';
|
||||
|
||||
toastr.options.positionClass = 'toast-top-right';
|
||||
toastr.options.preventDuplicates = true;
|
||||
|
||||
export default toastr;
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
73
themes/grav/gulpfile.js
Normal file
73
themes/grav/gulpfile.js
Normal file
@@ -0,0 +1,73 @@
|
||||
'use strict';
|
||||
|
||||
var gulp = require('gulp'),
|
||||
path = require('path'),
|
||||
immutable = require('immutable'),
|
||||
merge = require('merge-stream'),
|
||||
gulpWebpack = require('gulp-webpack'),
|
||||
webpack = require('webpack');
|
||||
|
||||
var plugins = {
|
||||
'Promise': 'imports?this=>global!exports?global.Promise!babel-polyfill',
|
||||
'fetch': 'imports?this=>global!exports?global.fetch!whatwg-fetch'
|
||||
},
|
||||
base = immutable.fromJS(require('./webpack.conf.js')),
|
||||
options = {
|
||||
dev: base.mergeDeep({
|
||||
devtool: 'source-map',
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': { NODE_ENV: '"development"' }
|
||||
}),
|
||||
new webpack.ProvidePlugin(plugins),
|
||||
new webpack.optimize.CommonsChunkPlugin("vendor", "vendor.js", Infinity)
|
||||
],
|
||||
output: {
|
||||
filename: 'admin.js'
|
||||
}
|
||||
}),
|
||||
|
||||
prod: base.mergeDeep({
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': { NODE_ENV: '"production"' }
|
||||
}),
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
sourceMap: false,
|
||||
compress: {
|
||||
warnings: false
|
||||
}
|
||||
}),
|
||||
new webpack.ProvidePlugin(plugins),
|
||||
new webpack.optimize.CommonsChunkPlugin("vendor", "vendor.min.js", Infinity)
|
||||
],
|
||||
output: {
|
||||
filename: 'admin.min.js'
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
var compileJS = function(watch) {
|
||||
var devOpts = options.dev.set('watch', watch),
|
||||
prodOpts = options.prod.set('watch', watch);
|
||||
|
||||
var prod = gulp.src('app/main.js')
|
||||
.pipe(gulpWebpack(prodOpts.toJS()))
|
||||
.pipe(gulp.dest('js/'));
|
||||
|
||||
var dev = gulp.src('app/main.js')
|
||||
.pipe(gulpWebpack(devOpts.toJS()))
|
||||
.pipe(gulp.dest('js/'));
|
||||
|
||||
return merge(prod, dev);
|
||||
};
|
||||
|
||||
gulp.task('js', function() {
|
||||
compileJS(false);
|
||||
});
|
||||
|
||||
gulp.task('watch', function() {
|
||||
compileJS(true);
|
||||
});
|
||||
|
||||
gulp.task('default', ['js']);
|
||||
@@ -1,4 +1,4 @@
|
||||
var getState = function(){
|
||||
/*var getState = function(){
|
||||
var loadValues = [],
|
||||
ignoreNames = ['page-filter', 'page-search'];
|
||||
$('input, select, textarea').each(function(index, element){
|
||||
@@ -9,37 +9,37 @@ var getState = function(){
|
||||
});
|
||||
|
||||
return loadValues.toString();
|
||||
};
|
||||
};*/
|
||||
|
||||
var bytesToSize = function(bytes) {
|
||||
/*var bytesToSize = function(bytes) {
|
||||
var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
||||
if (bytes == 0) return '0 Byte';
|
||||
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
|
||||
return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i];
|
||||
};
|
||||
};*/
|
||||
|
||||
var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
||||
/*var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
||||
|
||||
var keepAlive = function keepAlive() {
|
||||
$.post(GravAdmin.config.base_url_relative + '/task' + GravAdmin.config.param_sep + 'keepAlive', {
|
||||
'admin-nonce': GravAdmin.config.admin_nonce
|
||||
});
|
||||
};
|
||||
};*/
|
||||
|
||||
$(function () {
|
||||
jQuery.substitute = function(str, sub) {
|
||||
/*jQuery.substitute = function(str, sub) {
|
||||
return str.replace(/\{(.+?)\}/g, function($0, $1) {
|
||||
return $1 in sub ? sub[$1] : $0;
|
||||
});
|
||||
};
|
||||
};*/
|
||||
|
||||
// Set Toastr defaults
|
||||
toastr.options = {
|
||||
/*toastr.options = {
|
||||
"positionClass": "toast-top-right"
|
||||
}
|
||||
}*/
|
||||
|
||||
// dashboard
|
||||
var chart = $('.updates-chart'), UpdatesChart;
|
||||
/*var chart = $('.updates-chart'), UpdatesChart;
|
||||
if (chart.length) {
|
||||
var data = {
|
||||
series: [100, 0]
|
||||
@@ -60,17 +60,17 @@ $(function () {
|
||||
if (data.index) { return; }
|
||||
chart.find('.numeric span').text(Math.round(data.value) + '%');
|
||||
|
||||
var text = translations.PLUGIN_ADMIN.UPDATES_AVAILABLE;
|
||||
var text = GravAdmin.translations.PLUGIN_ADMIN.UPDATES_AVAILABLE;
|
||||
if (data.value == 100) {
|
||||
text = translations.PLUGIN_ADMIN.FULLY_UPDATED;
|
||||
text = GravAdmin.translations.PLUGIN_ADMIN.FULLY_UPDATED;
|
||||
}
|
||||
$('.js__updates-available-description').html(text)
|
||||
$('.updates-chart .hidden').removeClass('hidden');
|
||||
});
|
||||
}
|
||||
|
||||
*/
|
||||
// Cache Clear
|
||||
$('[data-clear-cache]').on('click', function(e) {
|
||||
/*$('[data-clear-cache]').on('click', function(e) {
|
||||
|
||||
$(this).attr('disabled','disabled').find('> .fa').removeClass('fa-trash').addClass('fa-refresh fa-spin');
|
||||
var url = $(this).data('clearCache');
|
||||
@@ -85,10 +85,10 @@ $(function () {
|
||||
}).always(function() {
|
||||
$('[data-clear-cache]').removeAttr('disabled').find('> .fa').removeClass('fa-refresh fa-spin').addClass('fa-trash');
|
||||
});
|
||||
});
|
||||
});*/
|
||||
|
||||
// Plugins list details sliders
|
||||
$('.gpm-name, .gpm-actions').on('click', function(e){
|
||||
/*$('.gpm-name, .gpm-actions').on('click', function(e){
|
||||
var target = $(e.target);
|
||||
|
||||
if (target.prop('tagName') == 'A' || target.parent('a').length) { return true; }
|
||||
@@ -105,10 +105,10 @@ $(function () {
|
||||
.addClass('fa-chevron-' + (isVisible ? 'up' : 'down'));
|
||||
}
|
||||
});
|
||||
});
|
||||
});*/
|
||||
|
||||
// Update plugins/themes
|
||||
$(document).on('click', '[data-maintenance-update]', function(e) {
|
||||
/*$(document).on('click', '[data-maintenance-update]', function(e) {
|
||||
|
||||
$(this).attr('disabled','disabled').find('> .fa').removeClass('fa-cloud-download').addClass('fa-refresh fa-spin');
|
||||
var url = $(this).data('maintenanceUpdate');
|
||||
@@ -125,9 +125,9 @@ $(function () {
|
||||
toastr.success(result.message + window.grav_available_version);
|
||||
$('#footer .grav-version').html(window.grav_available_version);
|
||||
|
||||
/*// hide the update button after successfull update and update the badges
|
||||
/!*!// hide the update button after successfull update and update the badges
|
||||
$('[data-maintenance-update]').fadeOut();
|
||||
$('.badges.with-updates').removeClass('with-updates').find('.badge.updates').remove();*/
|
||||
$('.badges.with-updates').removeClass('with-updates').find('.badge.updates').remove();*!/
|
||||
} else {
|
||||
toastr.success(result.message);
|
||||
}
|
||||
@@ -139,10 +139,10 @@ $(function () {
|
||||
GPMRefresh();
|
||||
$('[data-maintenance-update]').removeAttr('disabled').find('> .fa').removeClass('fa-refresh fa-spin').addClass('fa-cloud-download');
|
||||
});
|
||||
});
|
||||
});*/
|
||||
|
||||
// Update plugins/themes
|
||||
$('[data-ajax]').on('click', function(e) {
|
||||
/*$('[data-ajax]').on('click', function(e) {
|
||||
|
||||
var button = $(this),
|
||||
icon = button.find('> .fa'),
|
||||
@@ -182,7 +182,7 @@ $(function () {
|
||||
}
|
||||
}
|
||||
|
||||
toastr.success(result.message || translations.PLUGIN_ADMIN.TASK_COMPLETED);
|
||||
toastr.success(result.message || GravAdmin.translations.PLUGIN_ADMIN.TASK_COMPLETED);
|
||||
|
||||
for (var setting in toastrBackup) { if (toastrBackup.hasOwnProperty(setting)) {
|
||||
toastr.options[setting] = toastrBackup[setting];
|
||||
@@ -191,7 +191,7 @@ $(function () {
|
||||
|
||||
if (url.indexOf(task + 'backup') !== -1) {
|
||||
//Reset backup days count
|
||||
$('.backups-chart .numeric').html("0 <em>" + translations.PLUGIN_ADMIN.DAYS + "</em>");
|
||||
$('.backups-chart .numeric').html("0 <em>" + GravAdmin.translations.PLUGIN_ADMIN.DAYS + "</em>");
|
||||
|
||||
var data = {
|
||||
series: [0,100]
|
||||
@@ -214,9 +214,9 @@ $(function () {
|
||||
button.removeAttr('disabled');
|
||||
icon.removeClass('fa-refresh fa-spin').addClass(iconClasses.join(' '));
|
||||
});
|
||||
});
|
||||
});*/
|
||||
|
||||
$('[data-gpm-checkupdates]').on('click', function(){
|
||||
/*$('[data-gpm-checkupdates]').on('click', function(){
|
||||
var element = $(this);
|
||||
element.find('i').addClass('fa-spin');
|
||||
GPMRefresh({
|
||||
@@ -227,21 +227,21 @@ $(function () {
|
||||
|
||||
if (payload) {
|
||||
if (!payload.grav.isUpdatable && !payload.resources.total) {
|
||||
toastr.success(translations.PLUGIN_ADMIN.EVERYTHING_UP_TO_DATE);
|
||||
toastr.success(GravAdmin.translations.PLUGIN_ADMIN.EVERYTHING_UP_TO_DATE);
|
||||
} else {
|
||||
var grav = payload.grav.isUpdatable ? 'Grav v' + payload.grav.available : '';
|
||||
var resources = payload.resources.total ? payload.resources.total + ' ' + translations.PLUGIN_ADMIN.UPDATES_ARE_AVAILABLE: '';
|
||||
var resources = payload.resources.total ? payload.resources.total + ' ' + GravAdmin.translations.PLUGIN_ADMIN.UPDATES_ARE_AVAILABLE: '';
|
||||
|
||||
if (!resources) { grav += ' ' + translations.PLUGIN_ADMIN.IS_AVAILABLE_FOR_UPDATE }
|
||||
toastr.info(grav + (grav && resources ? ' ' + translations.PLUGIN_ADMIN.AND + ' ' : '') + resources);
|
||||
if (!resources) { grav += ' ' + GravAdmin.translations.PLUGIN_ADMIN.IS_AVAILABLE_FOR_UPDATE }
|
||||
toastr.info(grav + (grav && resources ? ' ' + GravAdmin.translations.PLUGIN_ADMIN.AND + ' ' : '') + resources);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});*/
|
||||
|
||||
var GPMRefresh = function (options) {
|
||||
options = options || {};
|
||||
/*options = options || {};
|
||||
|
||||
var data = {
|
||||
task: 'GPM',
|
||||
@@ -261,19 +261,19 @@ $(function () {
|
||||
return;
|
||||
}
|
||||
|
||||
var grav = response.payload.grav,
|
||||
/!*var grav = response.payload.grav,
|
||||
installed = response.payload.installed,
|
||||
resources = response.payload.resources,
|
||||
task = 'task' + GravAdmin.config.param_sep;
|
||||
|
||||
*!/
|
||||
// grav updatable
|
||||
if (grav.isUpdatable) {
|
||||
/!*if (grav.isUpdatable) {
|
||||
var icon = '<i class="fa fa-bullhorn"></i> ';
|
||||
content = 'Grav <b>v{available}</b> ' + translations.PLUGIN_ADMIN.IS_NOW_AVAILABLE + '! <span class="less">(' + translations.PLUGIN_ADMIN.CURRENT + ': v{version})</span> ',
|
||||
button = '<button data-maintenance-update="' + GravAdmin.config.base_url_relative + '/update.json/' + task + 'updategrav/admin-nonce' + GravAdmin.config.param_sep + GravAdmin.config.admin_nonce + '" class="button button-small secondary" id="grav-update-button">' + translations.PLUGIN_ADMIN.UPDATE_GRAV_NOW + '</button>';
|
||||
content = 'Grav <b>v{available}</b> ' + GravAdmin.translations.PLUGIN_ADMIN.IS_NOW_AVAILABLE + '! <span class="less">(' + GravAdmin.translations.PLUGIN_ADMIN.CURRENT + ': v{version})</span> ',
|
||||
button = '<button data-maintenance-update="' + GravAdmin.config.base_url_relative + '/update.json/' + task + 'updategrav/admin-nonce' + GravAdmin.config.param_sep + GravAdmin.config.admin_nonce + '" class="button button-small secondary" id="grav-update-button">' + GravAdmin.translations.PLUGIN_ADMIN.UPDATE_GRAV_NOW + '</button>';
|
||||
|
||||
if (grav.isSymlink) {
|
||||
button = '<span class="hint--left" style="float: right;" data-hint="' + translations.PLUGIN_ADMIN.GRAV_SYMBOLICALLY_LINKED + '"><i class="fa fa-fw fa-link"></i></span>';
|
||||
button = '<span class="hint--left" style="float: right;" data-hint="' + GravAdmin.translations.PLUGIN_ADMIN.GRAV_SYMBOLICALLY_LINKED + '"><i class="fa fa-fw fa-link"></i></span>';
|
||||
}
|
||||
|
||||
content = jQuery.substitute(content, {available: grav.available, version: grav.version});
|
||||
@@ -282,33 +282,33 @@ $(function () {
|
||||
}
|
||||
|
||||
$('#grav-update-button').on('click', function() {
|
||||
$(this).html(translations.PLUGIN_ADMIN.UPDATING_PLEASE_WAIT + ' ' + bytesToSize(grav.assets['grav-update'].size) + '..');
|
||||
});
|
||||
$(this).html(GravAdmin.translations.PLUGIN_ADMIN.UPDATING_PLEASE_WAIT + ' ' + bytesToSize(grav.assets['grav-update'].size) + '..');
|
||||
});*!/
|
||||
|
||||
// dashboard
|
||||
if ($('.updates-chart').length) {
|
||||
/!*if ($('.updates-chart').length) {
|
||||
var missing = (resources.total + (grav.isUpdatable ? 1 : 0)) * 100 / (installed + (grav.isUpdatable ? 1 : 0)),
|
||||
updated = 100 - missing;
|
||||
UpdatesChart.update({series: [updated, missing]});
|
||||
if (resources.total) {
|
||||
$('#updates [data-maintenance-update]').fadeIn();
|
||||
}
|
||||
}
|
||||
}*!/
|
||||
|
||||
if (!resources.total) {
|
||||
/!*if (!resources.total) {
|
||||
$('#updates [data-maintenance-update]').fadeOut();
|
||||
$('.badges.with-updates').removeClass('with-updates').find('.badge.updates').remove();
|
||||
} else {
|
||||
var length,
|
||||
icon = '<i class="fa fa-bullhorn"></i>',
|
||||
content = '{updates} ' + translations.PLUGIN_ADMIN.OF_YOUR + ' {type} ' + translations.PLUGIN_ADMIN.HAVE_AN_UPDATE_AVAILABLE,
|
||||
button = '<a href="{location}/' + task + 'update/admin-nonce' + GravAdmin.config.param_sep + GravAdmin.config.admin_nonce + '" class="button button-small secondary">' + translations.PLUGIN_ADMIN.UPDATE + ' {Type}</a>',
|
||||
content = '{updates} ' + GravAdmin.translations.PLUGIN_ADMIN.OF_YOUR + ' {type} ' + GravAdmin.translations.PLUGIN_ADMIN.HAVE_AN_UPDATE_AVAILABLE,
|
||||
button = '<a href="{location}/' + task + 'update/admin-nonce' + GravAdmin.config.param_sep + GravAdmin.config.admin_nonce + '" class="button button-small secondary">' + GravAdmin.translations.PLUGIN_ADMIN.UPDATE + ' {Type}</a>',
|
||||
plugins = $('.grav-update.plugins'),
|
||||
themes = $('.grav-update.themes'),
|
||||
sidebar = {plugins: $('#admin-menu a[href$="/plugins"]'), themes: $('#admin-menu a[href$="/themes"]')};
|
||||
|
||||
// sidebar
|
||||
if (sidebar.plugins.length || sidebar.themes.length) {
|
||||
/!*if (sidebar.plugins.length || sidebar.themes.length) {
|
||||
var length, badges;
|
||||
if (sidebar.plugins.length && (length = Object.keys(resources.plugins).length)) {
|
||||
badges = sidebar.plugins.find('.badges');
|
||||
@@ -321,7 +321,7 @@ $(function () {
|
||||
badges.addClass('with-updates');
|
||||
badges.find('.badge.updates').text(length);
|
||||
}
|
||||
}
|
||||
}*!/
|
||||
|
||||
// list page
|
||||
if (plugins[0] && (length = Object.keys(resources.plugins).length)) {
|
||||
@@ -334,7 +334,7 @@ $(function () {
|
||||
plugin = $('[data-gpm-plugin="' + key + '"] .gpm-name');
|
||||
url = plugin.find('a');
|
||||
if (!plugin.find('.badge.update').length) {
|
||||
plugin.append('<a class="plugin-update-button" href="' + url.attr('href') + '"><span class="badge update">' + translations.PLUGIN_ADMIN.UPDATE_AVAILABLE + '!</span></a>');
|
||||
plugin.append('<a class="plugin-update-button" href="' + url.attr('href') + '"><span class="badge update">' + GravAdmin.translations.PLUGIN_ADMIN.UPDATE_AVAILABLE + '!</span></a>');
|
||||
}
|
||||
|
||||
});
|
||||
@@ -349,12 +349,12 @@ $(function () {
|
||||
$.each(resources.themes, function (key, value) {
|
||||
theme = $('[data-gpm-theme="' + key + '"]');
|
||||
url = theme.find('.gpm-name a');
|
||||
theme.append('<div class="gpm-ribbon"><a href="' + url.attr('href') + '">' + translations.PLUGIN_ADMIN.UPDATE.toUpperCase() + '</a></div>');
|
||||
theme.append('<div class="gpm-ribbon"><a href="' + url.attr('href') + '">' + GravAdmin.translations.PLUGIN_ADMIN.UPDATE.toUpperCase() + '</a></div>');
|
||||
});
|
||||
}
|
||||
}*!/
|
||||
|
||||
// details page
|
||||
var type = 'plugin',
|
||||
/!*var type = 'plugin',
|
||||
details = $('.grav-update.plugin')[0];
|
||||
|
||||
if (!details) {
|
||||
@@ -368,7 +368,7 @@ $(function () {
|
||||
resource = resources[type + 's'][slug];
|
||||
|
||||
if (resource) {
|
||||
content = '<strong>v{available}</strong> ' + translations.PLUGIN_ADMIN.OF_THIS + ' ' + type + ' ' + translations.PLUGIN_ADMIN.IS_NOW_AVAILABLE + '!';
|
||||
content = '<strong>v{available}</strong> ' + GravAdmin.translations.PLUGIN_ADMIN.OF_THIS + ' ' + type + ' ' + GravAdmin.translations.PLUGIN_ADMIN.IS_NOW_AVAILABLE + '!';
|
||||
content = jQuery.substitute(content, { available: resource.available });
|
||||
button = jQuery.substitute(button, {
|
||||
Type: Type,
|
||||
@@ -376,21 +376,21 @@ $(function () {
|
||||
});
|
||||
$(details).html('<p>' + icon + content + button + '</p>');
|
||||
}
|
||||
}
|
||||
}
|
||||
}*!/
|
||||
//}
|
||||
|
||||
if (options.callback && typeof options.callback == 'function') options.callback(response);
|
||||
}
|
||||
}).always(function() {
|
||||
$('[data-gpm-checkupdates]').find('i').removeClass('fa-spin');
|
||||
});
|
||||
});*/
|
||||
};
|
||||
|
||||
if (GravAdmin.config.enable_auto_updates_check === '1') {
|
||||
/*if (GravAdmin.config.enable_auto_updates_check === '1') {
|
||||
GPMRefresh();
|
||||
}
|
||||
}*/
|
||||
|
||||
function reIndex (collection) {
|
||||
/*function reIndex (collection) {
|
||||
var holder = collection.find('[data-collection-holder]'),
|
||||
addBtn = collection.find('[data-action="add"]'),
|
||||
prefix = holder.data('collection-holder'),
|
||||
@@ -469,10 +469,10 @@ $(function () {
|
||||
MDEditors.add(field);
|
||||
}
|
||||
});
|
||||
});
|
||||
});*/
|
||||
|
||||
// enable the toggleable checkbox when typing in the corresponding textarea/input element
|
||||
jQuery(document).on('input propertychange click', '.form-data textarea, .form-data input, .form-data label, .form-data .selectize-input', function() {
|
||||
/*jQuery(document).on('input propertychange click', '.form-data textarea, .form-data input, .form-data label, .form-data .selectize-input', function() {
|
||||
var item = this;
|
||||
|
||||
var checkbox = $(item).parents('.form-field').find('.toggleable input[type="checkbox"]');
|
||||
@@ -501,26 +501,26 @@ $(function () {
|
||||
input.siblings('label').css('opacity', on ? 1 : 0.7);
|
||||
$(this).parents('.form-label').siblings('.form-data').css('opacity', on ? 1 : 0.7);
|
||||
|
||||
});
|
||||
});*/
|
||||
|
||||
// Themes Switcher Warning
|
||||
$(document).on('mousedown', '[data-remodal-target="theme-switch-warn"]', function(e){
|
||||
/*$(document).on('mousedown', '[data-remodal-target="theme-switch-warn"]', function(e){
|
||||
var name = $(e.target).closest('[data-gpm-theme]').find('.gpm-name a').text(),
|
||||
remodal = $('.remodal.theme-switcher');
|
||||
|
||||
remodal.find('strong').text(name);
|
||||
remodal.find('.button.continue').attr('href', $(e.target).attr('href'));
|
||||
});
|
||||
});*/
|
||||
|
||||
// Setup keep-alive on pages that have at least one element with data-grav-keepalive="true" set
|
||||
if ($(document).find('[data-grav-keepalive="true"]').length > 0) {
|
||||
/*if ($(document).find('[data-grav-keepalive="true"]').length > 0) {
|
||||
setInterval(function() {
|
||||
keepAlive();
|
||||
}, (GravAdmin.config.admin_timeout/2)*1000);
|
||||
}
|
||||
}*/
|
||||
|
||||
// CTRL + S / CMD + S - shortcut for [Save] when available
|
||||
var saveTask = $('[name="task"][value="save"]').filter(function(index, element) {
|
||||
/*var saveTask = $('[name="task"][value="save"]').filter(function(index, element) {
|
||||
return !($(element).parents('.remodal-overlay').length);
|
||||
});
|
||||
|
||||
@@ -532,5 +532,5 @@ $(function () {
|
||||
saveTask.click();
|
||||
}
|
||||
});
|
||||
}
|
||||
}*/
|
||||
});
|
||||
|
||||
13993
themes/grav/js/admin.js
Normal file
13993
themes/grav/js/admin.js
Normal file
File diff suppressed because it is too large
Load Diff
1
themes/grav/js/admin.js.map
Normal file
1
themes/grav/js/admin.js.map
Normal file
File diff suppressed because one or more lines are too long
6
themes/grav/js/admin.min.js
vendored
Normal file
6
themes/grav/js/admin.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -204,7 +204,7 @@
|
||||
this.scanned = true;
|
||||
|
||||
//Refresh root.currentValues as toggleables have been initialized
|
||||
root.currentValues = getState();
|
||||
// root.currentValues = getState();
|
||||
};
|
||||
|
||||
Form.factories = {};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
((function(){
|
||||
var toolbarIdentifiers = [ 'bold', 'italic', 'strike', 'link', 'image', 'blockquote', 'listUl', 'listOl' ];
|
||||
((function() {
|
||||
var toolbarIdentifiers = ['bold', 'italic', 'strike', 'link', 'image', 'blockquote', 'listUl', 'listOl'];
|
||||
if (typeof window.customToolbarElements !== 'undefined') {
|
||||
window.customToolbarElements.forEach(function(customToolbarElement) {
|
||||
toolbarIdentifiers.push(customToolbarElement.identifier);
|
||||
@@ -8,40 +8,40 @@
|
||||
|
||||
var toolbarButtons = {
|
||||
fullscreen: {
|
||||
title : 'Fullscreen',
|
||||
label : '<i class="fa fa-fw fa-expand"></i>'
|
||||
title: 'Fullscreen',
|
||||
label: '<i class="fa fa-fw fa-expand"></i>'
|
||||
},
|
||||
bold : {
|
||||
title : 'Bold',
|
||||
label : '<i class="fa fa-fw fa-bold"></i>'
|
||||
bold: {
|
||||
title: 'Bold',
|
||||
label: '<i class="fa fa-fw fa-bold"></i>'
|
||||
},
|
||||
italic : {
|
||||
title : 'Italic',
|
||||
label : '<i class="fa fa-fw fa-italic"></i>'
|
||||
italic: {
|
||||
title: 'Italic',
|
||||
label: '<i class="fa fa-fw fa-italic"></i>'
|
||||
},
|
||||
strike : {
|
||||
title : 'Strikethrough',
|
||||
label : '<i class="fa fa-fw fa-strikethrough"></i>'
|
||||
strike: {
|
||||
title: 'Strikethrough',
|
||||
label: '<i class="fa fa-fw fa-strikethrough"></i>'
|
||||
},
|
||||
blockquote : {
|
||||
title : 'Blockquote',
|
||||
label : '<i class="fa fa-fw fa-quote-right"></i>'
|
||||
blockquote: {
|
||||
title: 'Blockquote',
|
||||
label: '<i class="fa fa-fw fa-quote-right"></i>'
|
||||
},
|
||||
link : {
|
||||
title : 'Link',
|
||||
label : '<i class="fa fa-fw fa-link"></i>'
|
||||
link: {
|
||||
title: 'Link',
|
||||
label: '<i class="fa fa-fw fa-link"></i>'
|
||||
},
|
||||
image : {
|
||||
title : 'Image',
|
||||
label : '<i class="fa fa-fw fa-picture-o"></i>'
|
||||
image: {
|
||||
title: 'Image',
|
||||
label: '<i class="fa fa-fw fa-picture-o"></i>'
|
||||
},
|
||||
listUl : {
|
||||
title : 'Unordered List',
|
||||
label : '<i class="fa fa-fw fa-list-ul"></i>'
|
||||
listUl: {
|
||||
title: 'Unordered List',
|
||||
label: '<i class="fa fa-fw fa-list-ul"></i>'
|
||||
},
|
||||
listOl : {
|
||||
title : 'Ordered List',
|
||||
label : '<i class="fa fa-fw fa-list-ol"></i>'
|
||||
listOl: {
|
||||
title: 'Ordered List',
|
||||
label: '<i class="fa fa-fw fa-list-ol"></i>'
|
||||
}
|
||||
};
|
||||
|
||||
@@ -68,20 +68,34 @@
|
||||
|
||||
var template = '';
|
||||
|
||||
var MDEditor = function(editor, options){
|
||||
var MDEditor = function(editor, options) {
|
||||
var $this = this,
|
||||
task = 'task' + GravAdmin.config.param_sep;
|
||||
task = 'task' + GravAdmin.config.param_sep;
|
||||
|
||||
var tpl = ''
|
||||
|
||||
this.defaults = {
|
||||
markdown : false,
|
||||
autocomplete : true,
|
||||
height : 500,
|
||||
codemirror : { mode: 'htmlmixed', theme: 'paper', lineWrapping: true, dragDrop: true, autoCloseTags: true, matchTags: true, autoCloseBrackets: true, matchBrackets: true, indentUnit: 4, indentWithTabs: false, tabSize: 4, hintOptions: {completionSingle:false}, extraKeys: {"Enter": "newlineAndIndentContinueMarkdownList"} },
|
||||
toolbar : toolbarIdentifiers,
|
||||
lblPreview : '<i class="fa fa-fw fa-eye"></i>',
|
||||
lblCodeview : '<i class="fa fa-fw fa-code"></i>',
|
||||
markdown: false,
|
||||
autocomplete: true,
|
||||
height: 500,
|
||||
codemirror: {
|
||||
mode: 'htmlmixed',
|
||||
theme: 'paper',
|
||||
lineWrapping: true,
|
||||
dragDrop: true,
|
||||
autoCloseTags: true,
|
||||
matchTags: true,
|
||||
autoCloseBrackets: true,
|
||||
matchBrackets: true,
|
||||
indentUnit: 4,
|
||||
indentWithTabs: false,
|
||||
tabSize: 4,
|
||||
hintOptions: { completionSingle: false },
|
||||
extraKeys: { "Enter": "newlineAndIndentContinueMarkdownList" }
|
||||
},
|
||||
toolbar: toolbarIdentifiers,
|
||||
lblPreview: '<i class="fa fa-fw fa-eye"></i>',
|
||||
lblCodeview: '<i class="fa fa-fw fa-code"></i>',
|
||||
lblMarkedview: '<i class="fa fa-fw fa-code"></i>'
|
||||
};
|
||||
|
||||
@@ -89,14 +103,14 @@
|
||||
this.options = $.extend({}, this.defaults, options);
|
||||
|
||||
this.CodeMirror = CodeMirror;
|
||||
this.buttons = {};
|
||||
this.buttons = {};
|
||||
|
||||
template = [
|
||||
'<div class="grav-mdeditor clearfix" data-mode="tab" data-active-tab="code">',
|
||||
'<div class="grav-mdeditor-navbar">',
|
||||
'<ul class="grav-mdeditor-navbar-nav grav-mdeditor-toolbar"></ul>',
|
||||
'<div class="grav-mdeditor-navbar-flip">',
|
||||
'<ul class="grav-mdeditor-navbar-nav">'];
|
||||
'<div class="grav-mdeditor-navbar">',
|
||||
'<ul class="grav-mdeditor-navbar-nav grav-mdeditor-toolbar"></ul>',
|
||||
'<div class="grav-mdeditor-navbar-flip">',
|
||||
'<ul class="grav-mdeditor-navbar-nav">'];
|
||||
|
||||
if ($this.element.data('grav-preview-enabled')) {
|
||||
template.push('<li class="grav-mdeditor-button-code mdeditor-active"><a>{:lblCodeview}</a></li>');
|
||||
@@ -104,15 +118,15 @@
|
||||
}
|
||||
|
||||
template.push(
|
||||
'<li><a data-mdeditor-button="fullscreen"><i class="fa fa-fw fa-expand"></i></a></li>',
|
||||
'</ul>',
|
||||
'</div>',
|
||||
'<p class="grav-mdeditor-preview-text" style="display: none;">Preview</p>',
|
||||
'</div>',
|
||||
'<div class="grav-mdeditor-content">',
|
||||
'<div class="grav-mdeditor-code"></div>',
|
||||
'<div class="grav-mdeditor-preview"><div></div></div>',
|
||||
'</div>',
|
||||
'<li><a data-mdeditor-button="fullscreen"><i class="fa fa-fw fa-expand"></i></a></li>',
|
||||
'</ul>',
|
||||
'</div>',
|
||||
'<p class="grav-mdeditor-preview-text" style="display: none;">Preview</p>',
|
||||
'</div>',
|
||||
'<div class="grav-mdeditor-content">',
|
||||
'<div class="grav-mdeditor-code"></div>',
|
||||
'<div class="grav-mdeditor-preview"><div></div></div>',
|
||||
'</div>',
|
||||
'</div>'
|
||||
);
|
||||
|
||||
@@ -123,10 +137,10 @@
|
||||
tpl = tpl.replace(/\{:lblCodeview\}/g, this.options.lblCodeview);
|
||||
|
||||
this.mdeditor = $(tpl);
|
||||
this.content = this.mdeditor.find('.grav-mdeditor-content');
|
||||
this.toolbar = this.mdeditor.find('.grav-mdeditor-toolbar');
|
||||
this.preview = this.mdeditor.find('.grav-mdeditor-preview').children().eq(0);
|
||||
this.code = this.mdeditor.find('.grav-mdeditor-code');
|
||||
this.content = this.mdeditor.find('.grav-mdeditor-content');
|
||||
this.toolbar = this.mdeditor.find('.grav-mdeditor-toolbar');
|
||||
this.preview = this.mdeditor.find('.grav-mdeditor-preview').children().eq(0);
|
||||
this.code = this.mdeditor.find('.grav-mdeditor-code');
|
||||
|
||||
this.element.before(this.mdeditor).appendTo(this.code);
|
||||
this.editor = this.CodeMirror.fromTextArea(this.element[0], this.options.codemirror);
|
||||
@@ -170,7 +184,7 @@
|
||||
method: 'post',
|
||||
data: $this.element.parents('form').serialize(),
|
||||
toastErrors: true,
|
||||
success: function (response) {
|
||||
success: function(response) {
|
||||
$this.preview.container.html(response.message);
|
||||
}
|
||||
});
|
||||
@@ -222,11 +236,11 @@
|
||||
}, 100));
|
||||
}
|
||||
|
||||
this.debouncedRedraw = debounce(function () { $this.redraw(); }, 5);
|
||||
this.debouncedRedraw = debounce(function() { $this.redraw(); }, 5);
|
||||
|
||||
/*this.element.attr('data-grav-check-display', 1).on('grav-check-display', function(e) {
|
||||
if($this.mdeditor.is(":visible")) $this.fit();
|
||||
});*/
|
||||
if($this.mdeditor.is(":visible")) $this.fit();
|
||||
});*/
|
||||
|
||||
MDEditors.editors[this.element.attr('name')] = this;
|
||||
this.element.data('mdeditor_initialized', true);
|
||||
@@ -256,7 +270,7 @@
|
||||
var title = $this.buttons[button].title ? $this.buttons[button].title : button;
|
||||
var buttonClass = $this.buttons[button].class ? 'class="' + $this.buttons[button].class + '"' : '';
|
||||
|
||||
bar.push('<li><a data-mdeditor-button="'+button+'" title="'+title+'" '+buttonClass+' data-uk-tooltip>'+$this.buttons[button].label+'</a></li>');
|
||||
bar.push('<li><a data-mdeditor-button="' + button + '" title="' + title + '" ' + buttonClass + ' data-uk-tooltip>' + $this.buttons[button].label + '</a></li>');
|
||||
});
|
||||
|
||||
this.toolbar.html(bar.join('\n'));
|
||||
@@ -298,7 +312,7 @@
|
||||
};
|
||||
|
||||
this.getCursorMode = function() {
|
||||
var param = { mode: 'html'};
|
||||
var param = { mode: 'html' };
|
||||
this.element.trigger('cursorMode', [param]);
|
||||
return param.mode;
|
||||
};
|
||||
@@ -361,7 +375,13 @@
|
||||
var curWord = start != end && curLine.slice(start, end);
|
||||
|
||||
if (curWord) {
|
||||
this.editor.setSelection({ line: cur.line, ch: start}, { line: cur.line, ch: end });
|
||||
this.editor.setSelection({
|
||||
line: cur.line,
|
||||
ch: start
|
||||
}, {
|
||||
line: cur.line,
|
||||
ch: end
|
||||
});
|
||||
text = curWord;
|
||||
} else {
|
||||
indexOf = replace.indexOf('$1');
|
||||
@@ -372,10 +392,16 @@
|
||||
|
||||
this.editor.replaceSelection(html, 'end');
|
||||
if (indexOf !== -1) {
|
||||
this.editor.setCursor({ line: cur.line, ch: start + indexOf });
|
||||
this.editor.setCursor({
|
||||
line: cur.line,
|
||||
ch: start + indexOf
|
||||
});
|
||||
} else {
|
||||
if (action == 'link' || action == 'image') {
|
||||
this.editor.setCursor({ line: cur.line, ch: html.length -1 });
|
||||
this.editor.setCursor({
|
||||
line: cur.line,
|
||||
ch: html.length - 1
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -387,8 +413,17 @@
|
||||
text = this.editor.getLine(pos.line),
|
||||
html = replace.replace('$1', text);
|
||||
|
||||
this.editor.replaceRange(html , { line: pos.line, ch: 0 }, { line: pos.line, ch: text.length });
|
||||
this.editor.setCursor({ line: pos.line, ch: html.length });
|
||||
this.editor.replaceRange(html, {
|
||||
line: pos.line,
|
||||
ch: 0
|
||||
}, {
|
||||
line: pos.line,
|
||||
ch: text.length
|
||||
});
|
||||
this.editor.setCursor({
|
||||
line: pos.line,
|
||||
ch: html.length
|
||||
});
|
||||
this.editor.focus();
|
||||
};
|
||||
|
||||
@@ -410,15 +445,24 @@
|
||||
|
||||
if (editor.getCursorMode() == 'markdown') {
|
||||
|
||||
var cm = editor.editor,
|
||||
pos = cm.getDoc().getCursor(true),
|
||||
posend = cm.getDoc().getCursor(false);
|
||||
var cm = editor.editor,
|
||||
pos = cm.getDoc().getCursor(true),
|
||||
posend = cm.getDoc().getCursor(false);
|
||||
|
||||
for (var i=pos.line; i<(posend.line+1);i++) {
|
||||
cm.replaceRange('* '+cm.getLine(i), { line: i, ch: 0 }, { line: i, ch: cm.getLine(i).length });
|
||||
for (var i = pos.line; i < (posend.line + 1); i++) {
|
||||
cm.replaceRange('* ' + cm.getLine(i), {
|
||||
line: i,
|
||||
ch: 0
|
||||
}, {
|
||||
line: i,
|
||||
ch: cm.getLine(i).length
|
||||
});
|
||||
}
|
||||
|
||||
cm.setCursor({ line: posend.line, ch: cm.getLine(posend.line).length });
|
||||
cm.setCursor({
|
||||
line: posend.line,
|
||||
ch: cm.getLine(posend.line).length
|
||||
});
|
||||
cm.focus();
|
||||
}
|
||||
});
|
||||
@@ -427,25 +471,34 @@
|
||||
|
||||
if (editor.getCursorMode() == 'markdown') {
|
||||
|
||||
var cm = editor.editor,
|
||||
pos = cm.getDoc().getCursor(true),
|
||||
posend = cm.getDoc().getCursor(false),
|
||||
prefix = 1;
|
||||
var cm = editor.editor,
|
||||
pos = cm.getDoc().getCursor(true),
|
||||
posend = cm.getDoc().getCursor(false),
|
||||
prefix = 1;
|
||||
|
||||
if (pos.line > 0) {
|
||||
var prevline = cm.getLine(pos.line-1), matches;
|
||||
var prevline = cm.getLine(pos.line - 1), matches;
|
||||
|
||||
if(matches = prevline.match(/^(\d+)\./)) {
|
||||
prefix = Number(matches[1])+1;
|
||||
if (matches = prevline.match(/^(\d+)\./)) {
|
||||
prefix = Number(matches[1]) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (var i=pos.line; i<(posend.line+1);i++) {
|
||||
cm.replaceRange(prefix+'. '+cm.getLine(i), { line: i, ch: 0 }, { line: i, ch: cm.getLine(i).length });
|
||||
for (var i = pos.line; i < (posend.line + 1); i++) {
|
||||
cm.replaceRange(prefix + '. ' + cm.getLine(i), {
|
||||
line: i,
|
||||
ch: 0
|
||||
}, {
|
||||
line: i,
|
||||
ch: cm.getLine(i).length
|
||||
});
|
||||
prefix++;
|
||||
}
|
||||
|
||||
cm.setCursor({ line: posend.line, ch: cm.getLine(posend.line).length });
|
||||
cm.setCursor({
|
||||
line: posend.line,
|
||||
ch: cm.getLine(posend.line).length
|
||||
});
|
||||
cm.focus();
|
||||
}
|
||||
});
|
||||
@@ -485,8 +538,8 @@
|
||||
|
||||
// switch markdown mode on event
|
||||
editor.element.on({
|
||||
enableMarkdown : function() { editor.enableMarkdown(); },
|
||||
disableMarkdown : function() { editor.disableMarkdown(); }
|
||||
enableMarkdown: function() { editor.enableMarkdown(); },
|
||||
disableMarkdown: function() { editor.disableMarkdown(); }
|
||||
});
|
||||
|
||||
function enableMarkdown() {
|
||||
@@ -501,16 +554,22 @@
|
||||
|
||||
if (editor.mdeditor.hasClass('grav-mdeditor-fullscreen')) {
|
||||
|
||||
editor.editor.state.fullScreenRestore = {scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset, width: wrap.style.width, height: wrap.style.height};
|
||||
wrap.style.width = '';
|
||||
wrap.style.height = editor.content.height()+'px';
|
||||
editor.editor.state.fullScreenRestore = {
|
||||
scrollTop: window.pageYOffset,
|
||||
scrollLeft: window.pageXOffset,
|
||||
width: wrap.style.width,
|
||||
height: wrap.style.height
|
||||
};
|
||||
wrap.style.width = '';
|
||||
wrap.style.height = editor.content.height() + 'px';
|
||||
document.documentElement.style.overflow = 'hidden';
|
||||
|
||||
} else {
|
||||
|
||||
document.documentElement.style.overflow = '';
|
||||
var info = editor.editor.state.fullScreenRestore;
|
||||
wrap.style.width = info.width; wrap.style.height = info.height;
|
||||
wrap.style.width = info.width;
|
||||
wrap.style.height = info.height;
|
||||
window.scrollTo(info.scrollLeft, info.scrollTop);
|
||||
}
|
||||
|
||||
@@ -525,7 +584,7 @@
|
||||
editor.addShortcutAction('italic', ['Ctrl-I', 'Cmd-I']);
|
||||
|
||||
function addAction(name, replace, mode) {
|
||||
editor.element.on('action.'+name, function() {
|
||||
editor.element.on('action.' + name, function() {
|
||||
if (editor.getCursorMode() == 'markdown') {
|
||||
editor[mode == 'replaceLine' ? 'replaceLine' : 'replaceSelection'](replace, name);
|
||||
}
|
||||
@@ -553,20 +612,24 @@
|
||||
});
|
||||
},
|
||||
|
||||
add: function(editor) {
|
||||
editor = $(editor);
|
||||
add: function(editors) {
|
||||
editors = $(editors);
|
||||
|
||||
var mdeditor;
|
||||
if (!editor.data('mdeditor_initialized')) {
|
||||
mdeditor = new MDEditor(editor, JSON.parse(editor.attr('data-grav-mdeditor') || '{}'));
|
||||
}
|
||||
var mdeditor = [];
|
||||
|
||||
return mdeditor || MDEditors.editors[editor.attr('name')];
|
||||
editors.each(function(index, editor) {
|
||||
editor = $(editor);
|
||||
if (!editor.data('mdeditor_initialized')) {
|
||||
mdeditor.push(new MDEditor(editor, JSON.parse(editor.attr('data-grav-mdeditor') || '{}')));
|
||||
}
|
||||
});
|
||||
|
||||
return mdeditor || MDEditors.editors[editors.attr('name')];
|
||||
}
|
||||
};
|
||||
|
||||
// init
|
||||
$(function(){
|
||||
$(function() {
|
||||
MDEditors.init();
|
||||
});
|
||||
|
||||
|
||||
4
themes/grav/js/modernizr.custom.71422.js
vendored
4
themes/grav/js/modernizr.custom.71422.js
vendored
File diff suppressed because one or more lines are too long
@@ -3,189 +3,189 @@ $(function(){
|
||||
root = root.GravJS = root.GravJS || {};
|
||||
|
||||
//Make it global because used by ./forms/form.js
|
||||
root.currentValues = getState();
|
||||
var clickedLink;
|
||||
//root.currentValues = getState();
|
||||
//var clickedLink;
|
||||
|
||||
// selectize
|
||||
var pageFilter = $('input.page-filter'),
|
||||
pageTypes = pageFilter.data('template-types'),
|
||||
accessLevels = pageFilter.data('template-access-levels'),
|
||||
options = [
|
||||
{flag: 'Modular', key: 'Modular', cat: 'mode'},
|
||||
{flag: 'Visible', key: 'Visible', cat: 'mode'},
|
||||
{flag: 'Routable', key: 'Routable', cat: 'mode'},
|
||||
{flag: 'Published', key: 'Published', cat: 'mode'},
|
||||
{flag: 'Non-Modular', key: 'NonModular', cat: 'mode'},
|
||||
{flag: 'Non-Visible', key: 'NonVisible', cat: 'mode'},
|
||||
{flag: 'Non-Routable', key: 'NonRoutable', cat: 'mode'},
|
||||
{flag: 'Non-Published', key: 'NonPublished', cat: 'mode'},
|
||||
];
|
||||
/*var pageFilter = $('input.page-filter'),
|
||||
pageTypes = pageFilter.data('template-types'),
|
||||
accessLevels = pageFilter.data('template-access-levels'),
|
||||
options = [
|
||||
{flag: 'Modular', key: 'Modular', cat: 'mode'},
|
||||
{flag: 'Visible', key: 'Visible', cat: 'mode'},
|
||||
{flag: 'Routable', key: 'Routable', cat: 'mode'},
|
||||
{flag: 'Published', key: 'Published', cat: 'mode'},
|
||||
{flag: 'Non-Modular', key: 'NonModular', cat: 'mode'},
|
||||
{flag: 'Non-Visible', key: 'NonVisible', cat: 'mode'},
|
||||
{flag: 'Non-Routable', key: 'NonRoutable', cat: 'mode'},
|
||||
{flag: 'Non-Published', key: 'NonPublished', cat: 'mode'},
|
||||
];
|
||||
|
||||
if (pageFilter && pageTypes) {
|
||||
jQuery.each(pageTypes, function(key, name){
|
||||
options.push({flag: name, key: key, cat: 'type'});
|
||||
})
|
||||
if (pageFilter && pageTypes) {
|
||||
jQuery.each(pageTypes, function(key, name){
|
||||
options.push({flag: name, key: key, cat: 'type'});
|
||||
})
|
||||
|
||||
jQuery.each(accessLevels, function(key, name){
|
||||
options.push({flag: name, key: name, cat: 'access'});
|
||||
})
|
||||
jQuery.each(accessLevels, function(key, name){
|
||||
options.push({flag: name, key: name, cat: 'access'});
|
||||
})
|
||||
|
||||
pageFilter.selectize({
|
||||
maxItems: null,
|
||||
valueField: 'key',
|
||||
labelField: 'flag',
|
||||
searchField: ['flag', 'key'],
|
||||
options: options,
|
||||
optgroups: [
|
||||
{id: 'mode', name: translations.PLUGIN_ADMIN.PAGE_MODES},
|
||||
{id: 'type', name: translations.PLUGIN_ADMIN.PAGE_TYPES},
|
||||
{id: 'access', name: translations.PLUGIN_ADMIN.ACCESS_LEVELS},
|
||||
],
|
||||
optgroupField: 'cat',
|
||||
optgroupLabelField: 'name',
|
||||
optgroupValueField: 'id',
|
||||
optgroupOrder: ['mode', 'type', 'access'],
|
||||
plugins: ['optgroup_columns']
|
||||
});
|
||||
}
|
||||
pageFilter.selectize({
|
||||
maxItems: null,
|
||||
valueField: 'key',
|
||||
labelField: 'flag',
|
||||
searchField: ['flag', 'key'],
|
||||
options: options,
|
||||
optgroups: [
|
||||
{id: 'mode', name: translations.PLUGIN_ADMIN.PAGE_MODES},
|
||||
{id: 'type', name: translations.PLUGIN_ADMIN.PAGE_TYPES},
|
||||
{id: 'access', name: translations.PLUGIN_ADMIN.ACCESS_LEVELS},
|
||||
],
|
||||
optgroupField: 'cat',
|
||||
optgroupLabelField: 'name',
|
||||
optgroupValueField: 'id',
|
||||
optgroupOrder: ['mode', 'type', 'access'],
|
||||
plugins: ['optgroup_columns']
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
sessionStorage.setItem('sessionStorage', 1);
|
||||
sessionStorage.removeItem('sessionStorage');
|
||||
} catch (e) {
|
||||
Storage.prototype._setItem = Storage.prototype.setItem;
|
||||
Storage.prototype.setItem = function() {};
|
||||
}
|
||||
try {
|
||||
sessionStorage.setItem('sessionStorage', 1);
|
||||
sessionStorage.removeItem('sessionStorage');
|
||||
} catch (e) {
|
||||
Storage.prototype._setItem = Storage.prototype.setItem;
|
||||
Storage.prototype.setItem = function() {};
|
||||
}
|
||||
|
||||
var childrenToggles = $('[data-toggle="children"]'),
|
||||
storage = sessionStorage.getItem('grav:admin:pages'),
|
||||
collapseAll = function(store) {
|
||||
childrenToggles.each(function(i, element){
|
||||
var icon = $(element).find('.page-icon'),
|
||||
open = icon.hasClass('children-open'),
|
||||
key = $(element).closest('[data-nav-id]').data('nav-id'),
|
||||
children = $(element).closest('li.page-item').find('ul:first');
|
||||
var childrenToggles = $('[data-toggle="children"]'),
|
||||
storage = sessionStorage.getItem('grav:admin:pages'),
|
||||
collapseAll = function(store) {
|
||||
childrenToggles.each(function(i, element){
|
||||
var icon = $(element).find('.page-icon'),
|
||||
open = icon.hasClass('children-open'),
|
||||
key = $(element).closest('[data-nav-id]').data('nav-id'),
|
||||
children = $(element).closest('li.page-item').find('ul:first');
|
||||
|
||||
if (open) {
|
||||
children.hide();
|
||||
if (store) delete storage[key];
|
||||
icon.removeClass('children-open').addClass('children-closed');
|
||||
}
|
||||
if (open) {
|
||||
children.hide();
|
||||
if (store) delete storage[key];
|
||||
icon.removeClass('children-open').addClass('children-closed');
|
||||
}
|
||||
|
||||
if (store) sessionStorage.setItem('grav:admin:pages', JSON.stringify(storage));
|
||||
});
|
||||
},
|
||||
expandAll = function(store) {
|
||||
childrenToggles.each(function(i, element){
|
||||
var icon = $(element).find('.page-icon'),
|
||||
open = icon.hasClass('children-open'),
|
||||
key = $(element).closest('[data-nav-id]').data('nav-id'),
|
||||
children = $(element).closest('li.page-item').find('ul:first');
|
||||
if (store) sessionStorage.setItem('grav:admin:pages', JSON.stringify(storage));
|
||||
});
|
||||
},
|
||||
expandAll = function(store) {
|
||||
childrenToggles.each(function(i, element){
|
||||
var icon = $(element).find('.page-icon'),
|
||||
open = icon.hasClass('children-open'),
|
||||
key = $(element).closest('[data-nav-id]').data('nav-id'),
|
||||
children = $(element).closest('li.page-item').find('ul:first');
|
||||
|
||||
if (!open) {
|
||||
children.show();
|
||||
if (store) storage[key] = 1;
|
||||
icon.removeClass('children-closed').addClass('children-open');
|
||||
}
|
||||
if (!open) {
|
||||
children.show();
|
||||
if (store) storage[key] = 1;
|
||||
icon.removeClass('children-closed').addClass('children-open');
|
||||
}
|
||||
|
||||
if (store) sessionStorage.setItem('grav:admin:pages', JSON.stringify(storage));
|
||||
});
|
||||
},
|
||||
restoreStates = function() {
|
||||
collapseAll();
|
||||
for (var key in storage) {
|
||||
var element = $('[data-nav-id="' + key + '"]'),
|
||||
icon = element.find('.page-icon').first(),
|
||||
open = icon.hasClass('children-open'),
|
||||
children = element.closest('li.page-item').find('ul:first');
|
||||
if (store) sessionStorage.setItem('grav:admin:pages', JSON.stringify(storage));
|
||||
});
|
||||
},
|
||||
restoreStates = function() {
|
||||
collapseAll();
|
||||
for (var key in storage) {
|
||||
var element = $('[data-nav-id="' + key + '"]'),
|
||||
icon = element.find('.page-icon').first(),
|
||||
open = icon.hasClass('children-open'),
|
||||
children = element.closest('li.page-item').find('ul:first');
|
||||
|
||||
children.show();
|
||||
icon.removeClass('children-closed').addClass('children-open');
|
||||
}
|
||||
};
|
||||
children.show();
|
||||
icon.removeClass('children-closed').addClass('children-open');
|
||||
}
|
||||
};
|
||||
|
||||
if (!storage) {
|
||||
sessionStorage.setItem('grav:admin:pages', (storage = '{}'));
|
||||
}
|
||||
if (!storage) {
|
||||
sessionStorage.setItem('grav:admin:pages', (storage = '{}'));
|
||||
}
|
||||
|
||||
storage = JSON.parse(storage);
|
||||
storage = JSON.parse(storage);
|
||||
|
||||
restoreStates();
|
||||
restoreStates();
|
||||
|
||||
var startFilterPages = function () {
|
||||
var task = 'task' + GravAdmin.config.param_sep;
|
||||
var startFilterPages = function () {
|
||||
var task = 'task' + GravAdmin.config.param_sep;
|
||||
|
||||
$('input[name="page-search"]').focus();
|
||||
var flags = $('input[name="page-filter"]').val(),
|
||||
query = $('input[name="page-search"]').val();
|
||||
$('input[name="page-search"]').focus();
|
||||
var flags = $('input[name="page-filter"]').val(),
|
||||
query = $('input[name="page-search"]').val();
|
||||
|
||||
if (!flags.length && !query.length) {
|
||||
GravAjax.jqxhr.abort();
|
||||
return finishFilterPages([], true);
|
||||
}
|
||||
if (!flags.length && !query.length) {
|
||||
GravAjax.jqxhr.abort();
|
||||
return finishFilterPages([], true);
|
||||
}
|
||||
|
||||
GravAjax({
|
||||
dataType: 'json',
|
||||
method: 'POST',
|
||||
url: GravAdmin.config.base_url_relative + '/pages-filter.json/' + task + 'filterPages',
|
||||
data: {
|
||||
flags: flags,
|
||||
query: query,
|
||||
'admin-nonce': GravAdmin.config.admin_nonce
|
||||
},
|
||||
toastErrors: true,
|
||||
success: function (result, status) {
|
||||
finishFilterPages(result.results);
|
||||
}
|
||||
});
|
||||
};
|
||||
GravAjax({
|
||||
dataType: 'json',
|
||||
method: 'POST',
|
||||
url: GravAdmin.config.base_url_relative + '/pages-filter.json/' + task + 'filterPages',
|
||||
data: {
|
||||
flags: flags,
|
||||
query: query,
|
||||
'admin-nonce': GravAdmin.config.admin_nonce
|
||||
},
|
||||
toastErrors: true,
|
||||
success: function (result, status) {
|
||||
finishFilterPages(result.results);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var finishFilterPages = function (pages, reset) {
|
||||
var items = $('[data-nav-id]');
|
||||
var finishFilterPages = function (pages, reset) {
|
||||
var items = $('[data-nav-id]');
|
||||
|
||||
items.removeClass('search-match');
|
||||
items.removeClass('search-match');
|
||||
|
||||
if (reset) {
|
||||
items.addClass('search-match');
|
||||
restoreStates();
|
||||
} else {
|
||||
pages.forEach(function (id) {
|
||||
var match = items.filter('[data-nav-id="' + id + '"]'),
|
||||
parents = match.parents('[data-nav-id]');
|
||||
match.addClass('search-match');
|
||||
match.find('[data-nav-id]').addClass('search-match');
|
||||
parents.addClass('search-match');
|
||||
parents.find('[data-toggle="children"]').each(function(index, element){
|
||||
var icon = $(this).find('.page-icon'),
|
||||
open = icon.hasClass('children-open'),
|
||||
children = $(this).closest('li.page-item').find('ul:first');
|
||||
if (reset) {
|
||||
items.addClass('search-match');
|
||||
restoreStates();
|
||||
} else {
|
||||
pages.forEach(function (id) {
|
||||
var match = items.filter('[data-nav-id="' + id + '"]'),
|
||||
parents = match.parents('[data-nav-id]');
|
||||
match.addClass('search-match');
|
||||
match.find('[data-nav-id]').addClass('search-match');
|
||||
parents.addClass('search-match');
|
||||
parents.find('[data-toggle="children"]').each(function(index, element){
|
||||
var icon = $(this).find('.page-icon'),
|
||||
open = icon.hasClass('children-open'),
|
||||
children = $(this).closest('li.page-item').find('ul:first');
|
||||
|
||||
if (!open) {
|
||||
children.show();
|
||||
icon.removeClass('children-closed').addClass('children-open');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
if (!open) {
|
||||
children.show();
|
||||
icon.removeClass('children-closed').addClass('children-open');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
items.each(function (key, item) {
|
||||
if ($(item).hasClass('search-match')) {
|
||||
$(item).show();
|
||||
} else {
|
||||
$(item).hide();
|
||||
}
|
||||
});
|
||||
};
|
||||
items.each(function (key, item) {
|
||||
if ($(item).hasClass('search-match')) {
|
||||
$(item).show();
|
||||
} else {
|
||||
$(item).hide();
|
||||
}
|
||||
});
|
||||
};*/
|
||||
|
||||
// selectize
|
||||
$('input[name="page-search"]').on('input', startFilterPages);
|
||||
$('input[name="page-filter"]').on('change', startFilterPages);
|
||||
/*$('input[name="page-search"]').on('input', startFilterPages);
|
||||
$('input[name="page-filter"]').on('change', startFilterPages);*/
|
||||
|
||||
|
||||
// auto generate folder based on title
|
||||
// on user input on folder, autogeneration stops
|
||||
// if user empties the folder, autogeneration restarts
|
||||
$('input[name="folder"]').on('input', function(){
|
||||
/*$('input[name="folder"]').on('input', function(){
|
||||
$(this).data('user-custom-folder', true);
|
||||
if (!$(this).val()) $(this).data('user-custom-folder', false);
|
||||
});
|
||||
@@ -209,105 +209,108 @@ $(function(){
|
||||
|
||||
// restore cursor position
|
||||
this.setSelectionRange(start, end);
|
||||
});
|
||||
});*/
|
||||
|
||||
childrenToggles.on('click', function () {
|
||||
var icon = $(this).find('.page-icon'),
|
||||
open = icon.hasClass('children-open'),
|
||||
key = $(this).closest('[data-nav-id]').data('nav-id'),
|
||||
children = $(this).closest('li.page-item').find('ul:first');
|
||||
/* childrenToggles.on('click', function () {
|
||||
var icon = $(this).find('.page-icon'),
|
||||
open = icon.hasClass('children-open'),
|
||||
key = $(this).closest('[data-nav-id]').data('nav-id'),
|
||||
children = $(this).closest('li.page-item').find('ul:first');
|
||||
|
||||
if (open) {
|
||||
children.hide();
|
||||
delete storage[key];
|
||||
icon.removeClass('children-open').addClass('children-closed');
|
||||
} else {
|
||||
children.show();
|
||||
storage[key] = true;
|
||||
icon.removeClass('children-closed').addClass('children-open');
|
||||
}
|
||||
|
||||
sessionStorage.setItem('grav:admin:pages', JSON.stringify(storage));
|
||||
});
|
||||
|
||||
$('[data-page-toggleall]').on('click', function() {
|
||||
var state = $(this).data('page-toggleall');
|
||||
if (state == 'collapse') collapseAll(true);
|
||||
else expandAll(true);
|
||||
});
|
||||
if (open) {
|
||||
children.hide();
|
||||
delete storage[key];
|
||||
icon.removeClass('children-open').addClass('children-closed');
|
||||
} else {
|
||||
children.show();
|
||||
storage[key] = true;
|
||||
icon.removeClass('children-closed').addClass('children-open');
|
||||
}
|
||||
|
||||
sessionStorage.setItem('grav:admin:pages', JSON.stringify(storage));
|
||||
});
|
||||
*/
|
||||
/*$('[data-page-toggleall]').on('click', function() {
|
||||
var state = $(this).data('page-toggleall');
|
||||
if (state == 'collapse') collapseAll(true);
|
||||
else expandAll(true);
|
||||
});
|
||||
*/
|
||||
/*
|
||||
UNKNOWN
|
||||
$('#admin-main button').on('click', function(){
|
||||
$(window).off('beforeunload');
|
||||
});
|
||||
|
||||
$('[data-remodal-id] form').on('submit', function(){
|
||||
$(window).off('beforeunload');
|
||||
});
|
||||
});*/
|
||||
|
||||
$("#admin-mode-toggle input[name=mode-switch]").on('change', function(e){
|
||||
var value = $(this).val(),
|
||||
uri = $(this).data('leave-url');
|
||||
/*$("#admin-mode-toggle input[name=mode-switch]").on('change', function(e){
|
||||
var value = $(this).val(),
|
||||
uri = $(this).data('leave-url');
|
||||
|
||||
if (root.currentValues == getState()) {
|
||||
setTimeout(function(){
|
||||
window.location.href = uri;
|
||||
}, 200)
|
||||
if (root.currentValues == getState()) {
|
||||
setTimeout(function(){
|
||||
window.location.href = uri;
|
||||
}, 200)
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
e.preventDefault();
|
||||
|
||||
var confirm = $.remodal.lookup[$('[data-remodal-id=changes]').data('remodal')],
|
||||
buttons = $('[data-remodal-id=changes] a.button'),
|
||||
action;
|
||||
var confirm = $.remodal.lookup[$('[data-remodal-id=changes]').data('remodal')],
|
||||
buttons = $('[data-remodal-id=changes] a.button'),
|
||||
action;
|
||||
|
||||
buttons.on('click', function(e){
|
||||
e.preventDefault();
|
||||
action = $(this).data('leave-action');
|
||||
buttons.on('click', function(e){
|
||||
e.preventDefault();
|
||||
action = $(this).data('leave-action');
|
||||
|
||||
buttons.off('click');
|
||||
confirm.close();
|
||||
buttons.off('click');
|
||||
confirm.close();
|
||||
|
||||
if (action == 'continue') {
|
||||
$(window).off('beforeunload');
|
||||
window.location.href = $("#admin-mode-toggle input[name=mode-switch]:checked").data('leave-url');
|
||||
} else {
|
||||
$('input[name=mode-switch][checked]').prop('checked', true);
|
||||
}
|
||||
});
|
||||
if (action == 'continue') {
|
||||
$(window).off('beforeunload');
|
||||
window.location.href = $("#admin-mode-toggle input[name=mode-switch]:checked").data('leave-url');
|
||||
} else {
|
||||
$('input[name=mode-switch][checked]').prop('checked', true);
|
||||
}
|
||||
});
|
||||
|
||||
confirm.open();
|
||||
});
|
||||
confirm.open();
|
||||
});*/
|
||||
|
||||
$('a[href]:not([href^="#"])').on('click', function(e){
|
||||
if (root.currentValues != getState()){
|
||||
e.preventDefault();
|
||||
/*$('a[href]:not([href^=#])').on('click', function(e){
|
||||
if (root.currentValues != getState()){
|
||||
e.preventDefault();
|
||||
|
||||
clickedLink = $(this).attr('href');
|
||||
clickedLink = $(this).attr('href');
|
||||
|
||||
var confirm = $.remodal.lookup[$('[data-remodal-id=changes]').data('remodal')],
|
||||
buttons = $('[data-remodal-id=changes] a.button'),
|
||||
action;
|
||||
var confirm = $.remodal.lookup[$('[data-remodal-id=changes]').data('remodal')],
|
||||
buttons = $('[data-remodal-id=changes] a.button'),
|
||||
action;
|
||||
|
||||
buttons.on('click', function(e){
|
||||
e.preventDefault();
|
||||
action = $(this).data('leave-action');
|
||||
buttons.on('click', function(e){
|
||||
e.preventDefault();
|
||||
action = $(this).data('leave-action');
|
||||
|
||||
buttons.off('click');
|
||||
confirm.close();
|
||||
buttons.off('click');
|
||||
confirm.close();
|
||||
|
||||
if (action == 'continue') {
|
||||
$(window).off('beforeunload');
|
||||
window.location.href = clickedLink;
|
||||
}
|
||||
});
|
||||
if (action == 'continue') {
|
||||
$(window).off('beforeunload');
|
||||
window.location.href = clickedLink;
|
||||
}
|
||||
});
|
||||
|
||||
confirm.open();
|
||||
}
|
||||
});
|
||||
confirm.open();
|
||||
}
|
||||
});*/
|
||||
|
||||
// deletion
|
||||
/*
|
||||
$('[data-remodal-target="delete"]').on('click', function(){
|
||||
var okdelete = $('[data-remodal-id=delete] a.button');
|
||||
|
||||
@@ -320,26 +323,26 @@ $(function(){
|
||||
|
||||
window.location.href = okdelete;
|
||||
confirm.close();
|
||||
});
|
||||
});*/
|
||||
|
||||
$(window).on('beforeunload', function(){
|
||||
if (root.currentValues != getState()){
|
||||
return "You have made changes on this page that you have not yet confirmed. If you navigate away from this page you will lose your unsaved changes";
|
||||
}
|
||||
});
|
||||
/*$(window).on('beforeunload', function(){
|
||||
if (root.currentValues != getState()){
|
||||
return "You have made changes on this page that you have not yet confirmed. If you navigate away from this page you will lose your unsaved changes";
|
||||
}
|
||||
});*/
|
||||
|
||||
// Move dropdown sync (on dropdown change)
|
||||
/*$('body').on('change', '[data-page-move] select', function(){
|
||||
var route = jQuery('form#blueprints').first().find('select[name="route"]'),
|
||||
value = $(this).val();
|
||||
if (route.length && route.val() !== value) {
|
||||
route.val(value);
|
||||
route.data('selectize').setValue(value);
|
||||
}
|
||||
});*/
|
||||
var route = jQuery('form#blueprints').first().find('select[name="route"]'),
|
||||
value = $(this).val();
|
||||
if (route.length && route.val() !== value) {
|
||||
route.val(value);
|
||||
route.data('selectize').setValue(value);
|
||||
}
|
||||
});*/
|
||||
|
||||
// Move dropdown sync (on continue)
|
||||
$('[data-page-move] button').on('click', function(){
|
||||
/*$('[data-page-move] button').on('click', function(){
|
||||
var route = jQuery('form#blueprints').first().find('select[name="route"]'),
|
||||
value = $('[data-page-move] select').val();
|
||||
if (route.length && route.val() !== value) {
|
||||
@@ -347,5 +350,5 @@ $(function(){
|
||||
route.val(value);
|
||||
if (selectize) selectize.setValue(value);
|
||||
}
|
||||
});
|
||||
});*/
|
||||
});
|
||||
|
||||
14642
themes/grav/js/vendor.js
Normal file
14642
themes/grav/js/vendor.js
Normal file
File diff suppressed because it is too large
Load Diff
1
themes/grav/js/vendor.js.map
Normal file
1
themes/grav/js/vendor.js.map
Normal file
File diff suppressed because one or more lines are too long
13
themes/grav/js/vendor.min.js
vendored
Normal file
13
themes/grav/js/vendor.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
43
themes/grav/package.json
Normal file
43
themes/grav/package.json
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"name": "grav-admin",
|
||||
"version": "1.0.0",
|
||||
"description": "Grav Admin",
|
||||
"repository": "https://github.com/getgrav/grav-admin",
|
||||
"main": "app/main.js",
|
||||
"scripts": {
|
||||
"watch": "webpack --watch --progress --colors --config webpack.conf.js",
|
||||
"dev": "webpack --progress --colors --config webpack.conf.js",
|
||||
"prod": "NODE_ENV=production webpack -p --config webpack.conf.js",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "RocketTheme, LLC",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bootstrap": "^3.3.6",
|
||||
"chartist": "^0.9.5",
|
||||
"debounce": "^1.0.0",
|
||||
"dropzone": "^4.2.0",
|
||||
"eonasdan-bootstrap-datetimepicker": "^4.15.35",
|
||||
"immutable": "^3.7.6",
|
||||
"jquery-slugify": "^1.2.3",
|
||||
"remodal": "^1.0.6",
|
||||
"selectize": "^0.12.1",
|
||||
"sortablejs": "^1.4.2",
|
||||
"toastr": "^2.1.2",
|
||||
"whatwg-fetch": "^0.10.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-core": "^6.3.26",
|
||||
"babel-loader": "^6.2.0",
|
||||
"babel-polyfill": "^6.3.14",
|
||||
"babel-preset-es2015": "^6.3.13",
|
||||
"eslint": "^1.10.3",
|
||||
"eslint-loader": "^1.1.1",
|
||||
"exports-loader": "^0.6.2",
|
||||
"gulp": "^3.9.0",
|
||||
"gulp-webpack": "^1.5.0",
|
||||
"imports-loader": "^0.6.5",
|
||||
"merge-stream": "^1.0.0",
|
||||
"webpack": "^1.12.9"
|
||||
}
|
||||
}
|
||||
@@ -13,101 +13,146 @@
|
||||
|
||||
/* Hide scroll bar */
|
||||
|
||||
html.remodal_lock, body.remodal_lock {
|
||||
html.remodal-is-locked {
|
||||
overflow: hidden;
|
||||
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
/* Anti FOUC */
|
||||
|
||||
.remodal, [data-remodal-id] {
|
||||
visibility: hidden;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Overlay necessary styles */
|
||||
|
||||
.remodal-overlay {
|
||||
position: fixed;
|
||||
z-index: 99999;
|
||||
top: -5000px;
|
||||
right: -5000px;
|
||||
bottom: -5000px;
|
||||
left: -5000px;
|
||||
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Necessary styles of the wrapper */
|
||||
|
||||
.remodal-wrapper {
|
||||
position: fixed;
|
||||
z-index: 100000;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 10000;
|
||||
left: 0;
|
||||
|
||||
display: none;
|
||||
overflow: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
text-align: center;
|
||||
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
&:after {
|
||||
display: inline-block;
|
||||
display: inline-block;
|
||||
|
||||
height: 100%;
|
||||
margin-left: -0.05em;
|
||||
content: '';
|
||||
}
|
||||
|
||||
/* Fix iPad, iPhone glitches */
|
||||
> * {
|
||||
-webkit-transform: translateZ(0px);
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
|
||||
/* Fix iPad, iPhone glitches */
|
||||
|
||||
.remodal-overlay,
|
||||
.remodal-wrapper {
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
|
||||
/* Modal dialog necessary styles */
|
||||
.remodal {
|
||||
position: relative;
|
||||
outline: none;
|
||||
text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
.remodal-is-initialized {
|
||||
/* Disable Anti-FOUC */
|
||||
display: inline-block;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/* Background for effects */
|
||||
/* ==========================================================================
|
||||
Remodal's default mobile first theme
|
||||
========================================================================== */
|
||||
|
||||
.remodal-bg {
|
||||
@include transition-property (filter);
|
||||
@include transition-duration(0.2s);
|
||||
@include transition-timing-function(linear);
|
||||
/* Default theme styles for the background */
|
||||
|
||||
.remodal-bg.remodal-is-opening,
|
||||
.remodal-bg.remodal-is-opened {
|
||||
@include filter(blur(3px));
|
||||
}
|
||||
|
||||
// body.remodal_active .remodal-bg {
|
||||
// @include filter(blur(5px));
|
||||
// }
|
||||
|
||||
/* Overlay default theme styles */
|
||||
/* Default theme styles of the overlay */
|
||||
|
||||
.remodal-overlay {
|
||||
opacity: 0;
|
||||
background: rgba(33, 36, 46, 0.8);
|
||||
@include transition(opacity 0.2s linear);
|
||||
background: rgba(43, 46, 56, 0.9);
|
||||
}
|
||||
|
||||
body.remodal_active .remodal-overlay {
|
||||
opacity: 1;
|
||||
.remodal-overlay.remodal-is-opening,
|
||||
.remodal-overlay.remodal-is-closing {
|
||||
animation-duration: 0.3s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
/* Modal dialog default theme styles */
|
||||
.remodal-overlay.remodal-is-opening {
|
||||
animation-name: remodal-overlay-opening-keyframes;
|
||||
}
|
||||
|
||||
.remodal-overlay.remodal-is-closing {
|
||||
animation-name: remodal-overlay-closing-keyframes;
|
||||
}
|
||||
|
||||
/* Default theme styles of the wrapper */
|
||||
|
||||
.remodal-wrapper {
|
||||
padding: 10px 10px 0;
|
||||
}
|
||||
|
||||
/* Default theme styles of the modal dialog */
|
||||
|
||||
.remodal {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
padding-top: 2rem;
|
||||
@include box-sizing(border-box);
|
||||
font-size: 16px;
|
||||
background: $content-bg;
|
||||
background-clip: padding-box;
|
||||
color: $content-fg;
|
||||
box-shadow: 0 10px 20px rgba(0,0,0,0.5);
|
||||
@include transform(scale(0.95));
|
||||
@include transition-property (transform);
|
||||
@include transition-duration(0.2s);
|
||||
@include transition-timing-function(linear);
|
||||
margin-bottom: 10px;
|
||||
padding: 35px;
|
||||
|
||||
transform: translate3d(0, 0, 0);
|
||||
|
||||
color: #2b2e38;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
body.remodal_active .remodal {
|
||||
@include transform(scale(1));
|
||||
.remodal.remodal-is-opening,
|
||||
.remodal.remodal-is-closing {
|
||||
animation-duration: 0.3s;
|
||||
animation-fill-mode: forwards;
|
||||
}
|
||||
|
||||
/* Modal dialog vertical align */
|
||||
.remodal, .remodal-overlay:after {
|
||||
.remodal.remodal-is-opening {
|
||||
animation-name: remodal-opening-keyframes;
|
||||
}
|
||||
|
||||
.remodal.remodal-is-closing {
|
||||
animation-name: remodal-closing-keyframes;
|
||||
}
|
||||
|
||||
/* Vertical align of the modal dialog */
|
||||
|
||||
.remodal,
|
||||
.remodal-wrapper:after {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
@@ -115,42 +160,174 @@ body.remodal_active .remodal {
|
||||
|
||||
.remodal-close {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
color: $content-fg;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
|
||||
@include transition(background 0.2s linear);
|
||||
}
|
||||
|
||||
.remodal-close:after {
|
||||
display: block;
|
||||
font-family: FontAwesome;
|
||||
content: "\f00d";
|
||||
overflow: visible;
|
||||
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
font-size: 28px;
|
||||
line-height: 28px;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s;
|
||||
text-decoration: none;
|
||||
|
||||
color: #95979c;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.remodal-close:hover, .remodal-close:active {
|
||||
color: darken($content-fg, 20%);
|
||||
.remodal-close:hover,
|
||||
.remodal-close:focus {
|
||||
color: #2b2e38;
|
||||
}
|
||||
|
||||
.remodal-close:before {
|
||||
font-family: Arial, "Helvetica CY", "Nimbus Sans L", sans-serif !important;
|
||||
font-size: 25px;
|
||||
line-height: 35px;
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
display: block;
|
||||
|
||||
width: 35px;
|
||||
|
||||
content: "\00d7";
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Dialog buttons */
|
||||
|
||||
/*.remodal-confirm,
|
||||
.remodal-cancel {
|
||||
font: inherit;
|
||||
|
||||
display: inline-block;
|
||||
overflow: visible;
|
||||
|
||||
min-width: 110px;
|
||||
margin: 0;
|
||||
padding: 12px 0;
|
||||
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
text-decoration: none;
|
||||
|
||||
border: 0;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.remodal-confirm {
|
||||
color: #fff;
|
||||
background: #81c784;
|
||||
}
|
||||
|
||||
.remodal-confirm:hover,
|
||||
.remodal-confirm:focus {
|
||||
background: #66bb6a;
|
||||
}
|
||||
|
||||
.remodal-cancel {
|
||||
color: #fff;
|
||||
background: #e57373;
|
||||
}
|
||||
|
||||
.remodal-cancel:hover,
|
||||
.remodal-cancel:focus {
|
||||
background: #ef5350;
|
||||
}
|
||||
|
||||
!* Remove inner padding and border in Firefox 4+ for the button tag. *!
|
||||
|
||||
.remodal-confirm::-moz-focus-inner,
|
||||
.remodal-cancel::-moz-focus-inner,
|
||||
.remodal-close::-moz-focus-inner {
|
||||
padding: 0;
|
||||
|
||||
border: 0;
|
||||
}*/
|
||||
|
||||
/* Keyframes
|
||||
========================================================================== */
|
||||
|
||||
@keyframes remodal-opening-keyframes {
|
||||
from {
|
||||
transform: scale(1.05);
|
||||
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: none;
|
||||
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes remodal-closing-keyframes {
|
||||
from {
|
||||
transform: scale(1);
|
||||
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
transform: scale(0.95);
|
||||
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes remodal-overlay-opening-keyframes {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes remodal-overlay-closing-keyframes {
|
||||
from {
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Media queries
|
||||
========================================================================== */
|
||||
|
||||
@media only screen and (min-width: 40.063em) /* min-width 641px */ {
|
||||
@media only screen and (min-width: 641px) {
|
||||
.remodal {
|
||||
max-width: 700px;
|
||||
margin: 20px auto;
|
||||
min-height: 0;
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
/* IE8
|
||||
========================================================================== */
|
||||
|
||||
.lt-ie9 .remodal-overlay {
|
||||
background: #2b2e38;
|
||||
}
|
||||
|
||||
.lt-ie9 .remodal {
|
||||
width: 700px;
|
||||
}
|
||||
|
||||
/********* GRAV CUSTOM ********/
|
||||
|
||||
.remodal {
|
||||
padding: 35px 0 0;
|
||||
text-align: left;
|
||||
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.3);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
{% do assets.addJs(theme_url~'/js/codemirror-compressed.js') %}
|
||||
{% do assets.addJs(theme_url~'/js/mdeditor.js') %}
|
||||
{#{% do assets.addJs(theme_url~'/js/codemirror-compressed.js') %}
|
||||
{% do assets.addJs(theme_url~'/js/mdeditor.js') %}#}
|
||||
{{ parent() }}
|
||||
{% endblock %}
|
||||
|
||||
@@ -69,5 +69,19 @@
|
||||
{% else %}
|
||||
{% include 'partials/blueprints.html.twig' with { blueprints: data.blueprints, data: data } %}
|
||||
{% endif %}
|
||||
|
||||
<div class="remodal" data-remodal-id="changes">
|
||||
<form>
|
||||
<h1>{{ "PLUGIN_ADMIN.MODAL_CHANGED_DETECTED_TITLE"|tu }}</h1>
|
||||
<p class="bigger">
|
||||
{{ "PLUGIN_ADMIN.MODAL_CHANGED_DETECTED_DESC"|tu }}
|
||||
</p>
|
||||
<br>
|
||||
<div class="button-bar">
|
||||
<a class="button secondary" data-leave-action="cancel" href="#"><i class="fa fa-fw fa-close"></i> {{ "PLUGIN_ADMIN.CANCEL"|tu }}</a>
|
||||
<a class="button" data-leave-action="continue" href="#"><i class="fa fa-fw fa-check"></i> {{ "PLUGIN_ADMIN.CONTINUE"|tu }}</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -6,15 +6,15 @@
|
||||
<div class="button-bar">
|
||||
{% if authorize(['admin.maintenance', 'admin.super']) %}
|
||||
<div class="button-group">
|
||||
<button data-clear-cache="{{ uri.addNonce(base_url_relative ~ '/cache.json/task' ~ config.system.param_sep ~ 'clearCache', 'admin-form', 'admin-nonce') }}" class="button"><i class="fa fa-trash"></i> {{ "PLUGIN_ADMIN.CLEAR_CACHE"|tu }}</button>
|
||||
<button data-clear-cache-type="" data-clear-cache="{{ uri.addNonce(base_url_relative ~ '/cache.json/task' ~ config.system.param_sep ~ 'clearCache', 'admin-form', 'admin-nonce') }}" class="button"><i class="fa fa-trash"></i> {{ "PLUGIN_ADMIN.CLEAR_CACHE"|tu }}</button>
|
||||
<button type="button" class="button dropdown-toggle" data-toggle="dropdown">
|
||||
<i class="fa fa-caret-down"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a data-clear-cache="{{ uri.addNonce(base_url_relative ~ '/cache.json/task' ~ config.system.param_sep ~ 'clearCache/cleartype' ~ config.system.param_sep ~ 'all', 'admin-form', 'admin-nonce') }}" href="#">{{ "PLUGIN_ADMIN.CLEAR_CACHE_ALL_CACHE"|tu }}</a></li>
|
||||
<li><a data-clear-cache="{{ uri.addNonce(base_url_relative ~ '/cache.json/task' ~ config.system.param_sep ~ 'clearCache/cleartype' ~ config.system.param_sep ~ 'assets-only', 'admin-form', 'admin-nonce') }}" href="#">{{ "PLUGIN_ADMIN.CLEAR_CACHE_ASSETS_ONLY"|tu }}</a></li>
|
||||
<li><a data-clear-cache="{{ uri.addNonce(base_url_relative ~ '/cache.json/task' ~ config.system.param_sep ~ 'clearCache/cleartype' ~ config.system.param_sep ~ 'images-only', 'admin-form', 'admin-nonce') }}" href="#">{{ "PLUGIN_ADMIN.CLEAR_CACHE_IMAGES_ONLY"|tu }}</a></li>
|
||||
<li><a data-clear-cache="{{ uri.addNonce(base_url_relative ~ '/cache.json/task' ~ config.system.param_sep ~ 'clearCache/cleartype' ~ config.system.param_sep ~ 'cache-only', 'admin-form', 'admin-nonce') }}" href="#">{{ "PLUGIN_ADMIN.CLEAR_CACHE_CACHE_ONLY"|tu }}</a></li>
|
||||
<li><a data-clear-cache-type="all" data-clear-cache="{{ uri.addNonce(base_url_relative ~ '/cache.json/task' ~ config.system.param_sep ~ 'clearCache/cleartype' ~ config.system.param_sep ~ 'all', 'admin-form', 'admin-nonce') }}" href="#">{{ "PLUGIN_ADMIN.CLEAR_CACHE_ALL_CACHE"|tu }}</a></li>
|
||||
<li><a data-clear-cache-type="assets-only" data-clear-cache="{{ uri.addNonce(base_url_relative ~ '/cache.json/task' ~ config.system.param_sep ~ 'clearCache/cleartype' ~ config.system.param_sep ~ 'assets-only', 'admin-form', 'admin-nonce') }}" href="#">{{ "PLUGIN_ADMIN.CLEAR_CACHE_ASSETS_ONLY"|tu }}</a></li>
|
||||
<li><a data-clear-cache-type="images-only" data-clear-cache="{{ uri.addNonce(base_url_relative ~ '/cache.json/task' ~ config.system.param_sep ~ 'clearCache/cleartype' ~ config.system.param_sep ~ 'images-only', 'admin-form', 'admin-nonce') }}" href="#">{{ "PLUGIN_ADMIN.CLEAR_CACHE_IMAGES_ONLY"|tu }}</a></li>
|
||||
<li><a data-clear-cache-type="cache-only" data-clear-cache="{{ uri.addNonce(base_url_relative ~ '/cache.json/task' ~ config.system.param_sep ~ 'clearCache/cleartype' ~ config.system.param_sep ~ 'cache-only', 'admin-form', 'admin-nonce') }}" href="#">{{ "PLUGIN_ADMIN.CLEAR_CACHE_CACHE_ONLY"|tu }}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
{% set originalValue = originalValue is defined ? originalValue : value %}
|
||||
{% set toggleableChecked = field.toggleable and (originalValue is not null and originalValue is not empty) %}
|
||||
{% set isDisabledToggleable = field.toggleable and not toggleableChecked %}
|
||||
{% set value = (value is null ? field.default : value) %}
|
||||
{% set vertical = field.style == 'vertical' %}
|
||||
|
||||
@@ -7,21 +9,21 @@
|
||||
{% endif %}
|
||||
|
||||
{% block field %}
|
||||
<div class="form-field grid{% if vertical %} vertical{% endif %}">
|
||||
<div class="form-field grid{% if vertical %} vertical{% endif %}{% if field.toggleable %} form-field-toggleable{% endif %}">
|
||||
{% block contents %}
|
||||
<div class="form-label{% if not vertical %} block size-1-3{% endif %}">
|
||||
{% if field.toggleable %}
|
||||
<span class="checkboxes toggleable" data-grav-field="toggleable" data-grav-field-name="{{ field.name|fieldName }}">
|
||||
<input type="checkbox"
|
||||
id="toggleable_{{ field.name }}"
|
||||
{% if originalValue is not null and originalValue is not empty %}value="1"{% endif %}
|
||||
{% if toggleableChecked %}value="1"{% endif %}
|
||||
name="toggleable_{{ (scope ~ field.name)|fieldName }}"
|
||||
{% if originalValue is not null and originalValue is not empty %}checked="checked"{% endif %}
|
||||
{% if toggleableChecked %}checked="checked"{% endif %}
|
||||
>
|
||||
<label for="toggleable_{{ field.name }}"></label>
|
||||
</span>
|
||||
{% endif %}
|
||||
<label class="{{ field.toggleable ? 'toggleable' : '' }}">
|
||||
<label class="{{ field.toggleable ? 'toggleable' : '' }}"{{ field.toggleable ? 'for="toggleable_' ~ field.name ~'"' : ''}}>
|
||||
{% block label %}
|
||||
{% if field.help %}
|
||||
<span class="hint--bottom" data-hint="{{ field.help|e|tu }}">{{ field.label|tu }}</span>
|
||||
@@ -35,7 +37,7 @@
|
||||
<div class="form-data{% if not vertical %} block size-2-3{% endif %}"
|
||||
{% block global_attributes %}
|
||||
data-grav-field="{{ field.type }}"
|
||||
data-grav-disabled="{{ originalValue is null ? 'true' : 'false' }}"
|
||||
data-grav-disabled="{{ toggleableChecked }}"
|
||||
data-grav-default="{{ field.default|json_encode()|e('html_attr') }}"
|
||||
{% endblock %}
|
||||
>
|
||||
@@ -51,7 +53,7 @@
|
||||
{% if field.classes is defined %}class="{{ field.classes }}" {% endif %}
|
||||
{% if field.id is defined %}id="{{ field.id|e }}" {% endif %}
|
||||
{% if field.style is defined %}style="{{ field.style|e }}" {% endif %}
|
||||
{% if field.disabled %}disabled="disabled"{% endif %}
|
||||
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
|
||||
{% if field.placeholder %}placeholder="{{ field.placeholder|tu }}"{% endif %}
|
||||
{% if field.autofocus in ['on', 'true', 1] %}autofocus="autofocus"{% endif %}
|
||||
{% if field.novalidate in ['on', 'true', 1] %}novalidate="novalidate"{% endif %}
|
||||
|
||||
@@ -7,55 +7,62 @@
|
||||
{{ parent() }}
|
||||
{% endblock %}
|
||||
|
||||
{% macro renderer(key, text, field) %}
|
||||
<div class="form-row{% if field.value_only %} array-field-value_only{% endif %}"
|
||||
data-grav-array-type="row">
|
||||
{% if field.value_only != true %}
|
||||
{% if key == '0' and text == '' %}
|
||||
{% set key = '' %}
|
||||
{% endif %}
|
||||
|
||||
<input
|
||||
data-grav-array-type="key"
|
||||
type="text" value="{{ key }}"
|
||||
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
|
||||
placeholder="{{ field.placeholder_key|e|tu }}" />
|
||||
{% endif %}
|
||||
|
||||
<input
|
||||
data-grav-array-type="value"
|
||||
type="text"
|
||||
name="{{ (field.name|fieldName) ~ '[' ~ key ~ ']' }}"
|
||||
placeholder="{{ field.placeholder_value|e|tu }}"
|
||||
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
|
||||
value={% if text == 'true' %}true{% elseif text == 'false' %}false{% else %}"{{ text|join(', ')|e }}"{% endif %} />
|
||||
|
||||
<span data-grav-array-action="rem" class="fa fa-minus"></span>
|
||||
<span data-grav-array-action="add" class="fa fa-plus"></span>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% block input %}
|
||||
{% import _self as array_field %}
|
||||
<div data-grav-array-type="container"{% if field.value_only %} data-grav-array-mode="value_only"{% endif %}>
|
||||
{% if value|length %}
|
||||
{% for key, text in value -%}
|
||||
<div class="form-row{% if field.value_only %} array-field-value_only{% endif %}" data-grav-array-type="row">
|
||||
|
||||
{% if text is iterable %}
|
||||
<div class="grid" style="display: flex">
|
||||
<div class="block size-1-4">
|
||||
<input data-grav-array-type="keyArray" type="text" value="{{ key }}" placeholder="{{ field.placeholder_key|e|tu }}" style="float: none; width: 90%" />
|
||||
</div>
|
||||
|
||||
<div class="block size-3-4">
|
||||
{% for subkey, subtext in text -%}
|
||||
<div class="form-row" data-grav-array-type="subrow">
|
||||
<input data-grav-array-type="keyArraySubelement" type="text" value="{{ subkey }}" />
|
||||
<input data-grav-array-type="value" type="text" subkey="{{ subkey }}" name="{{ (field.name|fieldName) ~ '[' ~ key ~ '][' ~ subkey ~ ']' }}" value="{{ subtext|join(', ')|e }}" />
|
||||
|
||||
<span data-grav-array-action="remArrayItem" class="fa fa-minus-square"></span>
|
||||
<span data-grav-array-action="addArrayItem" class="fa fa-plus-square"></span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<div class="form-row{% if field.value_only %} array-field-value_only{% endif %}" data-grav-array-type="subrow">
|
||||
<span data-grav-array-action="rem" class="fa fa-minus"></span>
|
||||
<span data-grav-array-action="add" class="fa fa-plus"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
{% if field.value_only != true %}
|
||||
{% if key == '0' and text == '' %}
|
||||
{% set key = '' %}
|
||||
{% endif %}
|
||||
|
||||
<input data-grav-array-type="key" type="text" value="{{ key }}" placeholder="{{ field.placeholder_key|e|tu }}" />
|
||||
{% endif %}
|
||||
|
||||
<input data-grav-array-type="value" type="text" name="{{ (field.name|fieldName) ~ '[' ~ key ~ ']' }}" value={% if text == 'true' %}true{% elseif text == 'false' %}false{% else %}"{{ text|join(', ')|e }}"{% endif %} placeholder="{{ field.placeholder_value|e|tu }}" />
|
||||
|
||||
<span data-grav-array-action="rem" class="fa fa-minus"></span>
|
||||
<span data-grav-array-action="add" class="fa fa-plus"></span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if text is not iterable %}
|
||||
{{ array_field.renderer(key, text, field) }}
|
||||
{% else %}
|
||||
{# Backward compatibility for nested arrays (metas) which are not supported anymore #}
|
||||
{% for subkey, subtext in text -%}
|
||||
{{ array_field.renderer(key ~ ':' ~ subkey, subtext, field) }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{%- else -%}
|
||||
{# Empty value, mock the entry field#}
|
||||
<div class="form-row" data-grav-array-type="row">
|
||||
<input data-grav-array-type="key" type="text" placeholder="{{ field.placeholder_key|e|tu }}" />
|
||||
<input data-grav-array-type="value" type="text" placeholder="{{ field.placeholder_value|e|tu }}" />
|
||||
<input
|
||||
data-grav-array-type="key"
|
||||
type="text"
|
||||
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
|
||||
placeholder="{{ field.placeholder_key|e|tu }}" />
|
||||
<input
|
||||
data-grav-array-type="value"
|
||||
type="text"
|
||||
name="{{ field.name|fieldName }}"
|
||||
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
|
||||
placeholder="{{ field.placeholder_value|e|tu }}" />
|
||||
<span data-grav-array-action="rem" class="fa fa-minus"></span>
|
||||
<span data-grav-array-action="add" class="fa fa-plus"></span>
|
||||
</div>
|
||||
|
||||
@@ -1 +1,8 @@
|
||||
<input data-grav-field="hidden" data-grav-disabled="false" type="hidden" class="input" name="{{ (scope ~ field.name)|fieldName }}" value="{{ blueprints.name }}" />
|
||||
<input
|
||||
data-grav-field="hidden"
|
||||
data-grav-disabled="false"
|
||||
type="hidden"
|
||||
class="input"
|
||||
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
|
||||
name="{{ (scope ~ field.name)|fieldName }}"
|
||||
value="{{ blueprints.name }}" />
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
{% if field.novalidate in ['on', 'true', 1] %}novalidate="novalidate"{% endif %}
|
||||
{% if field.validate.required in ['on', 'true', 1] %}required="required"{% endif %}
|
||||
{% if field.multiple in ['on', 'true', 1] %}multiple="multiple"{% endif %}
|
||||
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
|
||||
{% if field.form %}form="{{ field.form }}"{% endif %}
|
||||
>
|
||||
{% for key, text in field.options %}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
{% block input_attributes %}
|
||||
type="file"
|
||||
{% if files.accept %}accept="{{ files.accept|join(',') }}"{% endif %}
|
||||
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
|
||||
{{ parent() }}
|
||||
{% endblock %}
|
||||
/>
|
||||
|
||||
@@ -13,7 +13,10 @@
|
||||
</div>
|
||||
<div class="form-data">
|
||||
<div class="form-frontmatter-wrapper {{ field.size }}">
|
||||
<textarea name="{{ (scope ~ field.name)|fieldName }}" id="frontmatter">{{ value|join("\n") }}</textarea>
|
||||
<textarea
|
||||
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
|
||||
name="{{ (scope ~ field.name)|fieldName }}"
|
||||
id="frontmatter">{{ value|join("\n") }}</textarea>
|
||||
<div class="dragbar"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
{% set value = (value is null ? field.default : value) %}
|
||||
{% set name = scope ~ field.name %}
|
||||
{% set array = field.array is defined ? field.array : true %}
|
||||
{% set lastKey = null %}
|
||||
|
||||
<div class="form-field grid pure-g">
|
||||
<div class="form-field grid pure-g BLABLA">
|
||||
<div class="form-label block size-1-4 pure-u-1-4">
|
||||
<label>
|
||||
{% if field.help %}
|
||||
@@ -19,12 +17,6 @@
|
||||
<ul data-collection-holder="{{ name }}">
|
||||
{% if field.fields %}
|
||||
{% for key, val in value %}
|
||||
{% if array and (key matches '/^\\d+$/') == 0 %}
|
||||
{% set array = false %}
|
||||
{% set lastKey = -1 %}
|
||||
{% elseif array %}
|
||||
{% set lastKey = key %}
|
||||
{% endif %}
|
||||
{% set itemName = name ~ '.' ~ key %}
|
||||
<li data-collection-item="{{ itemName }}" data-collection-key="{{ key }}">
|
||||
{% for childName, child in field.fields %}
|
||||
@@ -63,48 +55,47 @@
|
||||
{% endif %}
|
||||
</ul>
|
||||
<div class="collection-actions">
|
||||
{% set lastKey = lastKey + 1 %}
|
||||
<button class="button" type="button" data-action="add" data-key-index="{{ lastKey }}"><i class="fa fa-plus"></i> Add item</button>
|
||||
<button class="button" type="button" data-action="add"><i class="fa fa-plus"></i> Add item</button>
|
||||
</div>
|
||||
|
||||
<script type="text/html" data-collection-template="new">
|
||||
<div style="display: none;" data-collection-template="new" data-collection-template-html="{%- filter replace({' ': ' ', '\n': ' '})|e('html_attr') -%}
|
||||
<li data-collection-item="{{ name ~ '.*' }}">
|
||||
{% if field.fields %}
|
||||
{% set itemName = name ~ '.*' %}
|
||||
{% for childName, child in field.fields %}
|
||||
{% if childName starts with '.' %}
|
||||
{% set childKey = childName|trim('.') %}
|
||||
{% set childName = itemName ~ childName %}
|
||||
{% else %}
|
||||
{% set childKey = childName %}
|
||||
{% set childName = childName|replace({'*': key}) %}
|
||||
{% endif %}
|
||||
{% set child = child|merge({ name: childName }) %}
|
||||
{%- if field.fields -%}
|
||||
{%- set itemName = name ~ '.*' -%}
|
||||
{%- for childName, child in field.fields -%}
|
||||
{%- if childName starts with '.' -%}
|
||||
{%- set childKey = childName|trim('.') -%}
|
||||
{%- set childName = itemName ~ childName -%}
|
||||
{%- else %}
|
||||
{%- set childKey = childName -%}
|
||||
{%- set childName = childName|replace({'*': key}) -%}
|
||||
{%- endif %}
|
||||
{%- set child = child|merge({ name: childName }) -%}
|
||||
|
||||
{% if child.type == 'key' %}
|
||||
{%
|
||||
{%- if child.type == 'key' -%}
|
||||
{%-
|
||||
include 'forms/fields/text/text.html.twig'
|
||||
with { field: child, value: null }
|
||||
%}
|
||||
{% elseif child.type %}
|
||||
{%
|
||||
-%}
|
||||
{%- elseif child.type -%}
|
||||
{%-
|
||||
include [
|
||||
"forms/fields/#{child.type}/#{child.type}.html.twig",
|
||||
'forms/fields/text/text.html.twig'
|
||||
] with { field: child, value: null }
|
||||
%}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
-%}
|
||||
{%- endif -%}
|
||||
{%- endfor %}
|
||||
<div class="item-actions">
|
||||
<i class="fa fa-bars"></i>
|
||||
<br />
|
||||
<i class="fa fa-trash-o" data-action="delete"></i>
|
||||
</div>
|
||||
{% endif %}
|
||||
{%- endif -%}
|
||||
</li>
|
||||
</script>
|
||||
{%- endfilter -%}"></div>
|
||||
|
||||
<div style="display: none;" data-collection-config="{{ name }}" data-collection-array="{{ array ? 'true' : 'false' }}"></div>
|
||||
<div style="display: none;" data-collection-config="{{ name }}"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,12 @@
|
||||
{% block field %}
|
||||
<div class="form-field">
|
||||
<div class="form-data form-markdown-wrapper cm-s-paper">
|
||||
<textarea data-grav-mdeditor="{{ { 'markdown': true }|json_encode|e('html_attr') }}" name="{{ (scope ~ field.name)|fieldName }}" {% if field.showPreview %}data-grav-preview-enabled="true"{% endif %} data-grav-urlpreview="{{ base_url }}/media/{{ admin.route|trim('/') }}.json">{{ value|join("\n")|e('html') }}</textarea>
|
||||
<textarea
|
||||
data-grav-mdeditor="{{ { 'markdown': true }|json_encode|e('html_attr') }}"
|
||||
name="{{ (scope ~ field.name)|fieldName }}"
|
||||
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
|
||||
{% if field.showPreview %}data-grav-preview-enabled="true"{% endif %}
|
||||
data-grav-urlpreview="{{ base_url }}/media/{{ admin.route|trim('/') }}.json">{{ value|join("\n")|e('html') }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -15,7 +15,12 @@
|
||||
</div>
|
||||
<div class="form-data block size-2-3 pure-u-2-3">
|
||||
<div class="form-order-wrapper {{ field.size }}">
|
||||
<input type="hidden" data-order name="{{ (scope ~ field.name)|fieldName }}" value="{{ value }}" />
|
||||
<input
|
||||
type="hidden"
|
||||
data-order
|
||||
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
|
||||
name="{{ (scope ~ field.name)|fieldName }}"
|
||||
value="{{ value }}" />
|
||||
{% if data.parent.header.content.items %}
|
||||
<span class="note">Parent setting order, ordering disabled</span>
|
||||
{% elseif not data.visible %}
|
||||
@@ -33,17 +38,4 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
jQuery(function(){
|
||||
var el = jQuery('#ordering');
|
||||
new Sortable(el[0], {
|
||||
filter: ".ignore",
|
||||
onUpdate: function(evt){
|
||||
var index = el.children().index(jQuery(evt.item)) + 1;
|
||||
jQuery('[data-order]').val(index);
|
||||
}
|
||||
// draggable: ".drag-handle"
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
|
||||
@@ -4,158 +4,8 @@
|
||||
<div class="form-field">
|
||||
<div class="form-data form-uploads-wrapper">
|
||||
<h3>{{ field.label|tu }}</h3>
|
||||
<div id="gravDropzone" class="dropzone"></div>
|
||||
<div id="grav-dropzone" class="dropzone"></div>
|
||||
<span>{{ value|join("\n") }}</span>
|
||||
<script>
|
||||
$(function(){
|
||||
var URI = $('[data-media-url]').data('media-url'), thisDropzone,
|
||||
modalError = function(args){
|
||||
if (args.data.status == 'error' || args.data.status == 'unauthorized'){
|
||||
|
||||
if (args.mode == 'addBack'){
|
||||
// let's add back the file
|
||||
if (args.file instanceof File) this.addFile(args.file);
|
||||
else {
|
||||
this.files.push(args.file);
|
||||
this.options.addedfile.call(this, args.file);
|
||||
this.options.thumbnail.call(this, args.file, args.file.extras.url);
|
||||
}
|
||||
} else if (args.mode == 'removeFile') {
|
||||
args.file.rejected = true;
|
||||
this.removeFile(args.file);
|
||||
}
|
||||
|
||||
// fire up the modal
|
||||
var modalContainer = $('[data-remodal-id=generic]');
|
||||
modalContainer.find('.error-content').html(args.msg);
|
||||
$.remodal.lookup[modalContainer.data('remodal')].open();
|
||||
}
|
||||
};
|
||||
Dropzone.autoDiscover = false;
|
||||
Dropzone.confirm = function(question, accepted, rejected) {
|
||||
var modalContainer = $('[data-remodal-id=delete-media]'),
|
||||
acceptHandler = function () {
|
||||
if (accepted) {
|
||||
accepted();
|
||||
}
|
||||
$(document).off('confirm', '[data-remodal-id=delete-media]', acceptHandler);
|
||||
$(document).off('cancel', '[data-remodal-id=delete-media]', rejectHandler);
|
||||
},
|
||||
rejectHandler = function () {
|
||||
if (rejected) {
|
||||
rejected();
|
||||
}
|
||||
$(document).off('confirm', '[data-remodal-id=delete-media]', acceptHandler);
|
||||
$(document).off('cancel', '[data-remodal-id=delete-media]', rejectHandler);
|
||||
};
|
||||
|
||||
$.remodal.lookup[modalContainer.data('remodal')].open();
|
||||
$(document).on('confirm', '[data-remodal-id=delete-media]', acceptHandler);
|
||||
$(document).on('cancel', '[data-remodal-id=delete-media]', rejectHandler);
|
||||
};
|
||||
Dropzone.options.gravDropzone = {
|
||||
addRemoveLinks: false,
|
||||
dictRemoveFileConfirmation: '[placeholder]',
|
||||
acceptedFiles: $('[data-media-types]').data('media-types'),
|
||||
previewTemplate: "<div class=\"dz-preview dz-file-preview\">\n <div class=\"dz-details\">\n " +
|
||||
"<div class=\"dz-filename\"><span data-dz-name></span></div>\n " +
|
||||
"<div class=\"dz-size\" data-dz-size></div>\n <img data-dz-thumbnail />\n </div>\n " +
|
||||
"<div class=\"dz-progress\"><span class=\"dz-upload\" data-dz-uploadprogress></span></div>\n "+
|
||||
"<div class=\"dz-success-mark\"><span>✔</span></div>\n <div class=\"dz-error-mark\"><span>✘</span></div>\n " +
|
||||
"<div class=\"dz-error-message\"><span data-dz-errormessage></span></div>\n" +
|
||||
"<a class=\"dz-remove\" href=\"javascript:undefined;\" data-dz-remove>Delete</a>\n" +
|
||||
"<a class=\"dz-insert\" href=\"javascript:undefined;\" data-dz-insert>Insert</a>\n</div>",
|
||||
init: function() {
|
||||
thisDropzone = this;
|
||||
$.get(URI + '/task{{ config.system.param_sep }}listmedia/admin-nonce{{ config.system.param_sep }}' + GravAdmin.config.admin_nonce, function(data) {
|
||||
|
||||
$.proxy(modalError, this, {
|
||||
data: data,
|
||||
msg: '<p>An error occurred while trying to list files</p><pre>'+data.message+'</pre>'
|
||||
})();
|
||||
|
||||
if (data.results) {
|
||||
$.each(data.results, function(filename, data){
|
||||
var mockFile = { name: filename, size: data.size, accepted: true, extras: data };
|
||||
thisDropzone.files.push(mockFile);
|
||||
thisDropzone.options.addedfile.call(thisDropzone, mockFile);
|
||||
|
||||
if (filename.toLowerCase().match(/\.(jpg|jpeg|png|gif)$/)) {
|
||||
thisDropzone.options.thumbnail.call(thisDropzone, mockFile, data.url);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$('.dz-preview').prop('draggable', 'true');
|
||||
});
|
||||
|
||||
this.on("complete", function(file) {
|
||||
if (file.accepted) {
|
||||
$('.dz-preview').prop('draggable', 'true');
|
||||
return;
|
||||
}
|
||||
var data = {status: 'error', message: 'Unsupported file type: ' + file.name.match(/\..+/).join('')};
|
||||
$.proxy(modalError, this, {
|
||||
file: file,
|
||||
data: data,
|
||||
mode: 'removeFile',
|
||||
msg: '<p>An error occurred while trying to add the file <strong>'+file.name+'</strong></p><pre>'+data.message+'</pre>'
|
||||
})();
|
||||
});
|
||||
|
||||
this.on('success', function(file, response){
|
||||
thisDropzone = this;
|
||||
$.proxy(modalError, this, {
|
||||
file: file,
|
||||
data: response,
|
||||
mode: 'removeFile',
|
||||
msg: '<p>An error occurred while trying to upload the file <strong>'+file.name+'</strong></p><pre>'+response.message+'</pre>'
|
||||
})();
|
||||
});
|
||||
|
||||
this.on('removedfile', function(file) {
|
||||
if (!file.accepted || file.rejected) return;
|
||||
thisDropzone = this;
|
||||
$.post(URI + '/task{{ config.system.param_sep }}delmedia', {filename: file.name, 'admin-nonce': GravAdmin.config.admin_nonce}, function(data){
|
||||
$.proxy(modalError, thisDropzone, {
|
||||
file: file,
|
||||
data: data,
|
||||
mode: 'addBack',
|
||||
msg: '<p>An error occurred while trying to remove the file <strong>'+file.name+'</strong></p><pre>'+data.message+'</pre>'
|
||||
})();
|
||||
});
|
||||
});
|
||||
|
||||
this.on('sending', function(file, xhr, formData){
|
||||
formData.append('admin-nonce', GravAdmin.config.admin_nonce);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var dropzone = new Dropzone("#gravDropzone", { url: URI + '/task{{ config.system.param_sep }}addmedia', createImageThumbnails: { thumbnailWidth: 150} });
|
||||
|
||||
$("#gravDropzone").delegate('.dz-preview', 'dragstart', function(e){
|
||||
var uri = encodeURI($(this).find('.dz-filename').text());
|
||||
uri = uri.replace(/\(/g, '%28');
|
||||
uri = uri.replace(/\)/g, '%29');
|
||||
|
||||
var shortcode = '';
|
||||
if (!uri.match(/\.(jpg|jpeg|png|gif)$/)) {
|
||||
shortcode = '[' + decodeURI(uri) + '](' + uri + ')';
|
||||
}
|
||||
|
||||
dropzone.disable();
|
||||
$(this).addClass('hide-backface');
|
||||
e.originalEvent.dataTransfer.effectAllowed = 'copy';
|
||||
e.originalEvent.dataTransfer.setData('text', shortcode);
|
||||
});
|
||||
|
||||
$("#gravDropzone").delegate('.dz-preview', 'dragend', function(e){
|
||||
dropzone.enable();
|
||||
$(this).removeClass('hide-backface');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
{% if field.classes is defined %}class="{{ field.classes }}" {% endif %}
|
||||
{% if field.id is defined %}id="{{ field.id|e }}" {% endif %}
|
||||
{% if field.style is defined %}style="{{ field.style|e }}" {% endif %}
|
||||
{% if field.disabled or files is empty %}disabled="disabled"{% endif %}
|
||||
{% if field.disabled or files is empty or isDisabledToggleable %}disabled="disabled"{% endif %}
|
||||
{% if field.autofocus in ['on', 'true', 1] %}autofocus="autofocus"{% endif %}
|
||||
{% if field.novalidate in ['on', 'true', 1] %}novalidate="novalidate"{% endif %}
|
||||
{% if field.validate.required in ['on', 'true', 1] %}required="required"{% endif %}
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
{% if field.novalidate in ['on', 'true', 1] %}novalidate="novalidate"{% endif %}
|
||||
{% if field.validate.required in ['on', 'true', 1] %}required="required"{% endif %}
|
||||
{% if field.multiple in ['on', 'true', 1] %}multiple="multiple"{% endif %}
|
||||
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
|
||||
>
|
||||
{{ _self.options(field,pages,value, 0) }}
|
||||
</select>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
{% endif %}
|
||||
|
||||
{% if field.fields %}
|
||||
{% for tab in field.fields %}<input type="radio" name="tab" id="tab{{ loop.index }}" class="tab-head" {{ active == loop.index ? 'checked="checked"' : '' }}/><label for="tab{{ loop.index }}">{% if grav.twig.twig.filters['tu'] is defined %}{{ tab.title|tu }}{% else %}{{ tab.title|t }}{% endif %}</label>{% endfor %}
|
||||
{% for tab in field.fields %}<input type="radio" name="tab" id="tab{{ loop.index }}" class="tab-head no-form" {{ active == loop.index ? 'checked="checked"' : '' }}/><label for="tab{{ loop.index }}">{% if grav.twig.twig.filters['tu'] is defined %}{{ tab.title|tu }}{% else %}{{ tab.title|t }}{% endif %}</label>{% endfor %}
|
||||
<div class="tab-body-wrapper">
|
||||
{% for field in field.fields %}
|
||||
{% set value = data.value(field.name) %}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
{% if field.novalidate in ['on', 'true', 1] %}novalidate="novalidate"{% endif %}
|
||||
{% if field.validate.required in ['on', 'true', 1] %}required="required"{% endif %}
|
||||
{% if field.multiple in ['on', 'true', 1] %}multiple="multiple"{% endif %}
|
||||
>
|
||||
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}>
|
||||
{% for key, text in options %}
|
||||
<option {% if key == value or text in value %}selected="selected"{% endif %} value="{{ field.multiple ? text : key }}">{{ text }}</option>
|
||||
{% endfor %}
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
{% if field.highlight is defined %}
|
||||
class="{{ field.highlight == '' ~ key ? 'highlight' : '' }}"
|
||||
{% endif %}
|
||||
{% if field.disabled or isDisabledToggleable %}disabled="disabled"{% endif %}
|
||||
{% if field.toggleable %}
|
||||
{% if '' ~ key == '' ~ value %}checked="checked" {% endif %}
|
||||
{% if value is defined and (key == 1 or key == '1') %}checked="checked" {% endif %}
|
||||
|
||||
@@ -40,14 +40,14 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
{% do assets.addJs(theme_url~'/js/pages-all.js') %}
|
||||
{#{% do assets.addJs(theme_url~'/js/pages-all.js') %}
|
||||
{% do assets.addJs(theme_url~'/js/speakingurl.min.js') %}
|
||||
{% do assets.addJs(theme_url~'/js/slugify.min.js') %}
|
||||
{% if mode == 'edit' %}
|
||||
{% do assets.addJs(theme_url~'/js/codemirror-compressed.js') %}
|
||||
{% do assets.addJs(theme_url~'/js/mdeditor.js') %}
|
||||
{% do assets.addJs(theme_url~'/js/dropzone.min.js') %}
|
||||
{% endif %}
|
||||
{% endif %}#}
|
||||
{{ parent() }}
|
||||
{% endblock %}
|
||||
|
||||
@@ -260,7 +260,7 @@
|
||||
{% else %}
|
||||
<form id="page-filtering">
|
||||
<div class="page-filters">
|
||||
<input type="text" data-template-types="{{ admin.types|merge(admin.modularTypes)|json_encode|e('html_attr') }}" data-template-access-levels="{{ admin.accessLevels|json_encode|e('html_attr') }}" placeholder="{{ "PLUGIN_ADMIN.ADD_FILTERS"|tu }}" class="page-filter" name="page-filter" />
|
||||
<input type="text" data-filter-labels="{{ [{'id': 'mode', 'name': 'PLUGIN_ADMIN.PAGE_MODES'|tu}, {'id': 'type', 'name': 'PLUGIN_ADMIN.PAGE_TYPES'|tu}, {'id': 'access', 'name': 'PLUGIN_ADMIN.PAGE_ACCESS_LEVELS'|tu}] |json_encode|e('html_attr')}}" data-filter-types="{{ admin.types|merge(admin.modularTypes)|json_encode|e('html_attr') }}" data-filter-access-levels="{{ admin.accessLevels|json_encode|e('html_attr') }}" placeholder="{{ "PLUGIN_ADMIN.ADD_FILTERS"|tu }}" class="page-filter" name="page-filter" />
|
||||
</div>
|
||||
<div class="page-search">
|
||||
<input type="text" placeholder="{{ "PLUGIN_ADMIN.SEARCH_PAGES"|tu }}" name="page-search" />
|
||||
@@ -314,7 +314,7 @@
|
||||
</p>
|
||||
<br>
|
||||
<div class="button-bar">
|
||||
<a class="button secondary remodal-cancel" href="#"><i class="fa fa-fw fa-close"></i> {{ "PLUGIN_ADMIN.CANCEL"|tu }}</a>
|
||||
<button data-remodal-action="cancel" class="button secondary remodal-cancel"><i class="fa fa-fw fa-close"></i> {{ "PLUGIN_ADMIN.CANCEL"|tu }}</button>
|
||||
<a class="button" data-delete-action href="#"><i class="fa fa-fw fa-check"></i> {{ "PLUGIN_ADMIN.CONTINUE"|tu }}</a>
|
||||
</div>
|
||||
</form>
|
||||
@@ -343,8 +343,8 @@
|
||||
</p>
|
||||
<br>
|
||||
<div class="button-bar">
|
||||
<a class="button secondary remodal-cancel" href="#"><i class="fa fa-fw fa-close"></i> {{ "PLUGIN_ADMIN.CANCEL"|tu }}</a>
|
||||
<a class="button remodal-confirm" href="#"><i class="fa fa-fw fa-check"></i> {{ "PLUGIN_ADMIN.CONTINUE"|tu }}</a>
|
||||
<button data-remodal-action="cancel" class="button secondary remodal-cancel"><i class="fa fa-fw fa-close"></i> {{ "PLUGIN_ADMIN.CANCEL"|tu }}</button>
|
||||
<button data-remodal-action="confirm" class="button remodal-confirm"><i class="fa fa-fw fa-check"></i> {{ "PLUGIN_ADMIN.CONTINUE"|tu }}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -37,7 +37,9 @@
|
||||
{% include 'partials/javascript-config.html.twig' %}
|
||||
{% block javascripts %}
|
||||
{% do assets.add('jquery',101) %}
|
||||
{% do assets.addJs(theme_url~'/js/modernizr.custom.71422.js') %}
|
||||
{% do assets.addJs(theme_url~'/js/vendor.js', { 'loading':'defer' }) %}
|
||||
{% do assets.addJs(theme_url~'/js/admin.js' , { 'loading':'defer' }) %}
|
||||
{#{% do assets.addJs(theme_url~'/js/modernizr.custom.71422.js') %}
|
||||
{% do assets.addJs(theme_url~'/js/chartist.min.js') %}
|
||||
{% do assets.addJs(theme_url~'/js/selectize.min.js') %}
|
||||
{% do assets.addJS(theme_url~'/js/sortable.min.js') %}
|
||||
@@ -58,11 +60,11 @@
|
||||
{% do assets.addJs(theme_url~'/js/forms/fields/selectize.js') %}
|
||||
{% do assets.addJs(theme_url~'/js/forms/fields/checkboxes.js') %}
|
||||
{% do assets.addJs(theme_url~'/js/forms/fields/toggle.js') %}
|
||||
{% do assets.addJs(theme_url~'/js/forms.js') %}
|
||||
{% do assets.addJs(theme_url~'/js/forms.js') %}#}
|
||||
|
||||
{% if browser.getBrowser == 'msie' or browser.getBrowser == 'edge' %}
|
||||
{#{% if browser.getBrowser == 'msie' or browser.getBrowser == 'edge' %}
|
||||
{% do assets.addJs(theme_url~'/js/form-attr.polyfill.js') %}
|
||||
{% endif %}
|
||||
{% endif %}#}
|
||||
|
||||
{{ assets.js() }}
|
||||
{% endblock %}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{{ dump(data.extra) }}
|
||||
{% if data.extra %}
|
||||
{% for name, value in data.extra %}
|
||||
{% if name not in ['_json','task','admin-nonce'] %}
|
||||
|
||||
@@ -5,38 +5,23 @@
|
||||
<div class="tertiary-accent default-box-shadow">
|
||||
<h1>{{ "PLUGIN_ADMIN.MAINTENANCE"|tu }}</h1>
|
||||
<div class="admin-update-charts">
|
||||
<div class="updates-chart">
|
||||
<div class="updates-chart" data-chart-name="updates" data-chart-type="pie" data-chart-data="{{ {'series': [100, 0]}|json_encode|e('html_attr') }}">
|
||||
<div class="chart-wrapper">
|
||||
<div class="ct-chart"></div>
|
||||
<span class="numeric hidden"><span>-</span><em>{{ "PLUGIN_ADMIN.UPDATED"|tu|lower }}</em></span>
|
||||
</div>
|
||||
<p class="js__updates-available-description"> </p>
|
||||
</div>
|
||||
<div class="backups-chart">
|
||||
<div class="backups-chart" data-chart-name="backups" data-chart-type="pie" data-chart-data="{{ {'series': [backup.chart_fill, backup.chart_empty]}|json_encode|e('html_attr') }}">
|
||||
<div class="chart-wrapper">
|
||||
<div class="ct-chart"></div>
|
||||
<script>
|
||||
var data = {
|
||||
series: [{{ backup.chart_fill }}, {{ backup.chart_empty }}]
|
||||
};
|
||||
var options = {
|
||||
donut: true,
|
||||
donutWidth: 10,
|
||||
startAngle: 0,
|
||||
total: 100,
|
||||
showLabel: false,
|
||||
height: 150,
|
||||
chartPadding: !isFirefox ? 5 : 10
|
||||
};
|
||||
Chartist.Pie('.backups-chart .ct-chart', data, options);
|
||||
</script>
|
||||
<span class="numeric">{{ backup.days }}<em>{{ "PLUGIN_ADMIN.DAYS"|tu|lower }}</em></span>
|
||||
</div>
|
||||
<p>{{ "PLUGIN_ADMIN.LAST_BACKUP"|tu }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flush-bottom button-bar">
|
||||
<button data-maintenance-update="{{ uri.addNonce(base_url_relative ~ '/update.json/task' ~ config.system.param_sep ~ 'update', 'admin-form', 'admin-nonce') }}" class="button" style="display: none"><i class="fa fa-cloud-download"></i> {{ "PLUGIN_ADMIN.UPDATE"|tu }}</button>
|
||||
<button data-maintenance-update="{{ uri.addNonce(base_url_relative ~ '/update.json/task' ~ config.system.param_sep ~ 'update', 'admin-form', 'admin-nonce') }}" class="button"><i class="fa fa-cloud-download"></i> {{ "PLUGIN_ADMIN.UPDATE"|tu }}</button>
|
||||
<button data-ajax="{{ uri.addNonce(base_url_relative ~ '/backup.json/task' ~ config.system.param_sep ~ 'backup', 'admin-form', 'admin-nonce') }}" class="button"><i class="fa fa-database"></i> {{ "PLUGIN_ADMIN.BACKUP"|tu }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,39 +1,8 @@
|
||||
{% if authorize(['admin.statistics', 'admin.super']) %}
|
||||
<div id="popularity" class="dashboard-item dashboard-right">
|
||||
<div id="popularity" class="dashboard-item dashboard-right" data-chart-name="popularity" data-chart-type="bar" data-chart-data="{{ {'series': [popularity.getDailyChartData['data']], 'labels': popularity.getDailyChartData['labels']}|json_encode|e('html_attr') }}">
|
||||
<div class="secondary-accent default-box-shadow">
|
||||
<h1>{{ "PLUGIN_ADMIN.STATISTICS"|tu }}</h1>
|
||||
<div class="ct-chart"></div>
|
||||
<script>
|
||||
var data = {
|
||||
labels: {{ popularity.getDailyChartData['labels'] }},
|
||||
series: [
|
||||
{{ popularity.getDailyChartData['data'] }}
|
||||
]
|
||||
};
|
||||
var options = {
|
||||
height: 164,
|
||||
chartPadding: !isFirefox ? 5 : 25,
|
||||
|
||||
axisX: {
|
||||
showGrid: false,
|
||||
labelOffset: {
|
||||
x: 0,
|
||||
y: 5
|
||||
}
|
||||
},
|
||||
axisY: {
|
||||
offset: 15,
|
||||
showLabel: true,
|
||||
showGrid: true,
|
||||
labelOffset: {
|
||||
x: 5,
|
||||
y: 5
|
||||
},
|
||||
scaleMinSpace: 20
|
||||
}
|
||||
};
|
||||
Chartist.Bar('#popularity .ct-chart', data, options);
|
||||
</script>
|
||||
<div class="flush-bottom button-bar stats-bar">
|
||||
<span class="stat">
|
||||
<b>{{ popularity.getDailyTotal }}</b>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
{% endfor %}
|
||||
|
||||
<div class="button-bar">
|
||||
<a class="button secondary remodal-cancel" href="#"><i class="fa fa-fw fa-close"></i> {{ "PLUGIN_ADMIN.CANCEL"|tu }}</a>
|
||||
<button data-remodal-action="cancel" class="button secondary remodal-cancel"><i class="fa fa-fw fa-close"></i> {{ "PLUGIN_ADMIN.CANCEL"|tu }}</button>
|
||||
<button class="button primary" name="task" value="save" form="blueprints">{{ "PLUGIN_ADMIN.CONTINUE"|tu }}</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -42,3 +42,17 @@
|
||||
<a class="button" href="{{ uri.addNonce(base_url_relative ~ '/plugins/' ~ plugin.slug ~ '/task' ~ config.system.param_sep ~ 'install', 'admin-form', 'admin-nonce') }}"><i class="fa fa-fw fa-plus"></i>{{ "PLUGIN_ADMIN.INSTALL_PLUGIN"|tu }}</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="remodal" data-remodal-id="changes">
|
||||
<form>
|
||||
<h1>{{ "PLUGIN_ADMIN.MODAL_CHANGED_DETECTED_TITLE"|tu }}</h1>
|
||||
<p class="bigger">
|
||||
{{ "PLUGIN_ADMIN.MODAL_CHANGED_DETECTED_DESC"|tu }}
|
||||
</p>
|
||||
<br>
|
||||
<div class="button-bar">
|
||||
<a class="button secondary" data-leave-action="cancel" href="#"><i class="fa fa-fw fa-close"></i> {{ "PLUGIN_ADMIN.CANCEL"|tu }}</a>
|
||||
<a class="button" data-leave-action="continue" href="#"><i class="fa fa-fw fa-check"></i> {{ "PLUGIN_ADMIN.CONTINUE"|tu }}</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -111,6 +111,16 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="remodal" data-remodal-id="changes">
|
||||
<form>
|
||||
<h1>{{ "PLUGIN_ADMIN.MODAL_CHANGED_DETECTED_TITLE"|tu }}</h1>
|
||||
<p class="bigger">
|
||||
{{ "PLUGIN_ADMIN.MODAL_CHANGED_DETECTED_DESC"|tu }}
|
||||
</p>
|
||||
<br>
|
||||
<div class="button-bar">
|
||||
<a class="button secondary" data-leave-action="cancel" href="#"><i class="fa fa-fw fa-close"></i> {{ "PLUGIN_ADMIN.CANCEL"|tu }}</a>
|
||||
<a class="button" data-leave-action="continue" href="#"><i class="fa fa-fw fa-check"></i> {{ "PLUGIN_ADMIN.CONTINUE"|tu }}</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
</p>
|
||||
<br>
|
||||
<div class="button-bar">
|
||||
<a class="button secondary remodal-cancel" href="#"><i class="fa fa-fw fa-close"></i> {{ "PLUGIN_ADMIN.CANCEL"|tu }}</a>
|
||||
<button data-remodal-action="cancel" class="button secondary remodal-cancel"><i class="fa fa-fw fa-close"></i> {{ "PLUGIN_ADMIN.CANCEL"|tu }}</button>
|
||||
<a class="button continue" href="#"><i class="fa fa-fw fa-check"></i>{{ "PLUGIN_ADMIN.CONTINUE"|tu }}</a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
{% do assets.addJs(theme_url~'/js/codemirror-compressed.js') %}
|
||||
{% do assets.addJs(theme_url~'/js/mdeditor.js') %}
|
||||
{#{% do assets.addJs(theme_url~'/js/codemirror-compressed.js') %}
|
||||
{% do assets.addJs(theme_url~'/js/mdeditor.js') %}#}
|
||||
{{ parent() }}
|
||||
{% endblock %}
|
||||
{% endif %}
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
{% do assets.addJs(theme_url~'/js/codemirror-compressed.js') %}
|
||||
{% do assets.addJs(theme_url~'/js/mdeditor.js') %}
|
||||
{#{% do assets.addJs(theme_url~'/js/codemirror-compressed.js') %}
|
||||
{% do assets.addJs(theme_url~'/js/mdeditor.js') %}#}
|
||||
{{ parent() }}
|
||||
{% endblock %}
|
||||
{% endif %}
|
||||
|
||||
44
themes/grav/webpack.conf.js
Normal file
44
themes/grav/webpack.conf.js
Normal file
@@ -0,0 +1,44 @@
|
||||
var path = require('path'),
|
||||
webpack = require('webpack');
|
||||
|
||||
module.exports = {
|
||||
entry: {
|
||||
app: './app/main.js',
|
||||
vendor: [
|
||||
'chartist',
|
||||
'selectize',
|
||||
'remodal',
|
||||
'toastr',
|
||||
'bootstrap',
|
||||
'sortablejs',
|
||||
'jquery-slugify',
|
||||
'dropzone',
|
||||
'eonasdan-bootstrap-datetimepicker'
|
||||
]
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'js'),
|
||||
library: 'Grav'
|
||||
},
|
||||
externals: {
|
||||
jquery: 'jQuery',
|
||||
'grav-config': 'GravAdmin'
|
||||
},
|
||||
module: {
|
||||
preLoaders: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: 'eslint',
|
||||
exclude: /node_modules/
|
||||
}
|
||||
],
|
||||
loaders: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: 'babel',
|
||||
exclude: /node_modules/,
|
||||
query: { presets: ['es2015'] }
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user