From 8c02f174a7d9f6ce32aa6064846ce3fccc5749dd Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Fri, 13 Dec 2019 15:35:44 +1100 Subject: [PATCH 001/157] Update FUNDING.yml --- .github/FUNDING.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index bc7c4b4be5..a29ace930d 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,5 +1,4 @@ # These are supported funding model platforms -custom: ['https://octobercms.com/fundraising'] +custom: ['https://octobercms.com/premium-support'] open_collective: octobercms github: LukeTowers -patreon: LukeTowers From ea99cb1d8096f1a78ee13bf94f454a0c5a041b35 Mon Sep 17 00:00:00 2001 From: Ayumi Hamasaki Date: Sat, 20 Apr 2019 01:13:27 +0100 Subject: [PATCH 002/157] Update Dropzone V4.0.1 to V5.5.1 This is a major update from V4 to V5 and will need some testing to make sure October CMS works ok with this update. --- .../assets/vendor/dropzone/dropzone.js | 4303 ++++++++++++----- 1 file changed, 3055 insertions(+), 1248 deletions(-) diff --git a/modules/backend/assets/vendor/dropzone/dropzone.js b/modules/backend/assets/vendor/dropzone/dropzone.js index babbdd450e..476c0550d1 100644 --- a/modules/backend/assets/vendor/dropzone/dropzone.js +++ b/modules/backend/assets/vendor/dropzone/dropzone.js @@ -1,3 +1,16 @@ +/** + * DropZone V5.5.1 (non-minified) for testing on October CMS + */ + +"use strict"; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /* * @@ -25,581 +38,1270 @@ * */ -(function() { - var Dropzone, Emitter, camelize, contentLoaded, detectVerticalSquash, drawImageIOSFix, noop, without, - __slice = [].slice, - __hasProp = {}.hasOwnProperty, - __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; - - noop = function() {}; - - Emitter = (function() { - function Emitter() {} +// The Emitter class provides the ability to call `.on()` on Dropzone to listen +// to events. +// It is strongly based on component's emitter class, and I removed the +// functionality because of the dependency hell with different frameworks. +var Emitter = function () { + function Emitter() { + _classCallCheck(this, Emitter); + } - Emitter.prototype.addEventListener = Emitter.prototype.on; + _createClass(Emitter, [{ + key: "on", - Emitter.prototype.on = function(event, fn) { + // Add an event listener for given event + value: function on(event, fn) { this._callbacks = this._callbacks || {}; + // Create namespace for this event if (!this._callbacks[event]) { this._callbacks[event] = []; } this._callbacks[event].push(fn); return this; - }; - - Emitter.prototype.emit = function() { - var args, callback, callbacks, event, _i, _len; - event = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + } + }, { + key: "emit", + value: function emit(event) { this._callbacks = this._callbacks || {}; - callbacks = this._callbacks[event]; + var callbacks = this._callbacks[event]; + if (callbacks) { - for (_i = 0, _len = callbacks.length; _i < _len; _i++) { - callback = callbacks[_i]; + for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + for (var _iterator = callbacks, _isArray = true, _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { + var _ref; + + if (_isArray) { + if (_i >= _iterator.length) break; + _ref = _iterator[_i++]; + } else { + _i = _iterator.next(); + if (_i.done) break; + _ref = _i.value; + } + + var callback = _ref; + callback.apply(this, args); } } - return this; - }; - - Emitter.prototype.removeListener = Emitter.prototype.off; - Emitter.prototype.removeAllListeners = Emitter.prototype.off; + return this; + } - Emitter.prototype.removeEventListener = Emitter.prototype.off; + // Remove event listener for given event. If fn is not provided, all event + // listeners for that event will be removed. If neither is provided, all + // event listeners will be removed. - Emitter.prototype.off = function(event, fn) { - var callback, callbacks, i, _i, _len; + }, { + key: "off", + value: function off(event, fn) { if (!this._callbacks || arguments.length === 0) { this._callbacks = {}; return this; } - callbacks = this._callbacks[event]; + + // specific event + var callbacks = this._callbacks[event]; if (!callbacks) { return this; } + + // remove all handlers if (arguments.length === 1) { delete this._callbacks[event]; return this; } - for (i = _i = 0, _len = callbacks.length; _i < _len; i = ++_i) { - callback = callbacks[i]; + + // remove specific handler + for (var i = 0; i < callbacks.length; i++) { + var callback = callbacks[i]; if (callback === fn) { callbacks.splice(i, 1); break; } } + return this; - }; + } + }]); - return Emitter; + return Emitter; +}(); - })(); +var Dropzone = function (_Emitter) { + _inherits(Dropzone, _Emitter); - Dropzone = (function(_super) { - var extend, resolveOption; + _createClass(Dropzone, null, [{ + key: "initClass", + value: function initClass() { - __extends(Dropzone, _super); + // Exposing the emitter class, mainly for tests + this.prototype.Emitter = Emitter; - Dropzone.prototype.Emitter = Emitter; + /* + This is a list of all available events you can register on a dropzone object. + You can register an event handler like this: + dropzone.on("dragEnter", function() { }); + */ + this.prototype.events = ["drop", "dragstart", "dragend", "dragenter", "dragover", "dragleave", "addedfile", "addedfiles", "removedfile", "thumbnail", "error", "errormultiple", "processing", "processingmultiple", "uploadprogress", "totaluploadprogress", "sending", "sendingmultiple", "success", "successmultiple", "canceled", "canceledmultiple", "complete", "completemultiple", "reset", "maxfilesexceeded", "maxfilesreached", "queuecomplete"]; + + this.prototype.defaultOptions = { + /** + * Has to be specified on elements other than form (or when the form + * doesn't have an `action` attribute). You can also + * provide a function that will be called with `files` and + * must return the url (since `v3.12.0`) + */ + url: null, + + /** + * Can be changed to `"put"` if necessary. You can also provide a function + * that will be called with `files` and must return the method (since `v3.12.0`). + */ + method: "post", + + /** + * Will be set on the XHRequest. + */ + withCredentials: false, + + /** + * The timeout for the XHR requests in milliseconds (since `v4.4.0`). + */ + timeout: 30000, + + /** + * How many file uploads to process in parallel (See the + * Enqueuing file uploads* documentation section for more info) + */ + parallelUploads: 2, + + /** + * Whether to send multiple files in one request. If + * this it set to true, then the fallback file input element will + * have the `multiple` attribute as well. This option will + * also trigger additional events (like `processingmultiple`). See the events + * documentation section for more information. + */ + uploadMultiple: false, + + /** + * Whether you want files to be uploaded in chunks to your server. This can't be + * used in combination with `uploadMultiple`. + * + * See [chunksUploaded](#config-chunksUploaded) for the callback to finalise an upload. + */ + chunking: false, + + /** + * If `chunking` is enabled, this defines whether **every** file should be chunked, + * even if the file size is below chunkSize. This means, that the additional chunk + * form data will be submitted and the `chunksUploaded` callback will be invoked. + */ + forceChunking: false, + + /** + * If `chunking` is `true`, then this defines the chunk size in bytes. + */ + chunkSize: 2000000, + + /** + * If `true`, the individual chunks of a file are being uploaded simultaneously. + */ + parallelChunkUploads: false, + + /** + * Whether a chunk should be retried if it fails. + */ + retryChunks: false, + + /** + * If `retryChunks` is true, how many times should it be retried. + */ + retryChunksLimit: 3, + + /** + * If not `null` defines how many files this Dropzone handles. If it exceeds, + * the event `maxfilesexceeded` will be called. The dropzone element gets the + * class `dz-max-files-reached` accordingly so you can provide visual feedback. + */ + maxFilesize: 256, + + /** + * The name of the file param that gets transferred. + * **NOTE**: If you have the option `uploadMultiple` set to `true`, then + * Dropzone will append `[]` to the name. + */ + paramName: "file", + + /** + * Whether thumbnails for images should be generated + */ + createImageThumbnails: true, + + /** + * In MB. When the filename exceeds this limit, the thumbnail will not be generated. + */ + maxThumbnailFilesize: 10, + + /** + * If `null`, the ratio of the image will be used to calculate it. + */ + thumbnailWidth: 120, + + /** + * The same as `thumbnailWidth`. If both are null, images will not be resized. + */ + thumbnailHeight: 120, + + /** + * How the images should be scaled down in case both, `thumbnailWidth` and `thumbnailHeight` are provided. + * Can be either `contain` or `crop`. + */ + thumbnailMethod: 'crop', + + /** + * If set, images will be resized to these dimensions before being **uploaded**. + * If only one, `resizeWidth` **or** `resizeHeight` is provided, the original aspect + * ratio of the file will be preserved. + * + * The `options.transformFile` function uses these options, so if the `transformFile` function + * is overridden, these options don't do anything. + */ + resizeWidth: null, + + /** + * See `resizeWidth`. + */ + resizeHeight: null, + + /** + * The mime type of the resized image (before it gets uploaded to the server). + * If `null` the original mime type will be used. To force jpeg, for example, use `image/jpeg`. + * See `resizeWidth` for more information. + */ + resizeMimeType: null, + + /** + * The quality of the resized images. See `resizeWidth`. + */ + resizeQuality: 0.8, + + /** + * How the images should be scaled down in case both, `resizeWidth` and `resizeHeight` are provided. + * Can be either `contain` or `crop`. + */ + resizeMethod: 'contain', + + /** + * The base that is used to calculate the filesize. You can change this to + * 1024 if you would rather display kibibytes, mebibytes, etc... + * 1024 is technically incorrect, because `1024 bytes` are `1 kibibyte` not `1 kilobyte`. + * You can change this to `1024` if you don't care about validity. + */ + filesizeBase: 1000, + + /** + * Can be used to limit the maximum number of files that will be handled by this Dropzone + */ + maxFiles: null, + + /** + * An optional object to send additional headers to the server. Eg: + * `{ "My-Awesome-Header": "header value" }` + */ + headers: null, + + /** + * If `true`, the dropzone element itself will be clickable, if `false` + * nothing will be clickable. + * + * You can also pass an HTML element, a CSS selector (for multiple elements) + * or an array of those. In that case, all of those elements will trigger an + * upload when clicked. + */ + clickable: true, + + /** + * Whether hidden files in directories should be ignored. + */ + ignoreHiddenFiles: true, + + /** + * The default implementation of `accept` checks the file's mime type or + * extension against this list. This is a comma separated list of mime + * types or file extensions. + * + * Eg.: `image/*,application/pdf,.psd` + * + * If the Dropzone is `clickable` this option will also be used as + * [`accept`](https://developer.mozilla.org/en-US/docs/HTML/Element/input#attr-accept) + * parameter on the hidden file input as well. + */ + acceptedFiles: null, + + /** + * **Deprecated!** + * Use acceptedFiles instead. + */ + acceptedMimeTypes: null, + + /** + * If false, files will be added to the queue but the queue will not be + * processed automatically. + * This can be useful if you need some additional user input before sending + * files (or if you want want all files sent at once). + * If you're ready to send the file simply call `myDropzone.processQueue()`. + * + * See the [enqueuing file uploads](#enqueuing-file-uploads) documentation + * section for more information. + */ + autoProcessQueue: true, + + /** + * If false, files added to the dropzone will not be queued by default. + * You'll have to call `enqueueFile(file)` manually. + */ + autoQueue: true, + + /** + * If `true`, this will add a link to every file preview to remove or cancel (if + * already uploading) the file. The `dictCancelUpload`, `dictCancelUploadConfirmation` + * and `dictRemoveFile` options are used for the wording. + */ + addRemoveLinks: false, + + /** + * Defines where to display the file previews – if `null` the + * Dropzone element itself is used. Can be a plain `HTMLElement` or a CSS + * selector. The element should have the `dropzone-previews` class so + * the previews are displayed properly. + */ + previewsContainer: null, + + /** + * This is the element the hidden input field (which is used when clicking on the + * dropzone to trigger file selection) will be appended to. This might + * be important in case you use frameworks to switch the content of your page. + * + * Can be a selector string, or an element directly. + */ + hiddenInputContainer: "body", + + /** + * If null, no capture type will be specified + * If camera, mobile devices will skip the file selection and choose camera + * If microphone, mobile devices will skip the file selection and choose the microphone + * If camcorder, mobile devices will skip the file selection and choose the camera in video mode + * On apple devices multiple must be set to false. AcceptedFiles may need to + * be set to an appropriate mime type (e.g. "image/*", "audio/*", or "video/*"). + */ + capture: null, + + /** + * **Deprecated**. Use `renameFile` instead. + */ + renameFilename: null, + + /** + * A function that is invoked before the file is uploaded to the server and renames the file. + * This function gets the `File` as argument and can use the `file.name`. The actual name of the + * file that gets used during the upload can be accessed through `file.upload.filename`. + */ + renameFile: null, + + /** + * If `true` the fallback will be forced. This is very useful to test your server + * implementations first and make sure that everything works as + * expected without dropzone if you experience problems, and to test + * how your fallbacks will look. + */ + forceFallback: false, + + /** + * The text used before any files are dropped. + */ + dictDefaultMessage: "Drop files here to upload", + + /** + * The text that replaces the default message text it the browser is not supported. + */ + dictFallbackMessage: "Your browser does not support drag'n'drop file uploads.", + + /** + * The text that will be added before the fallback form. + * If you provide a fallback element yourself, or if this option is `null` this will + * be ignored. + */ + dictFallbackText: "Please use the fallback form below to upload your files like in the olden days.", + + /** + * If the filesize is too big. + * `{{filesize}}` and `{{maxFilesize}}` will be replaced with the respective configuration values. + */ + dictFileTooBig: "File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.", + + /** + * If the file doesn't match the file type. + */ + dictInvalidFileType: "You can't upload files of this type.", + + /** + * If the server response was invalid. + * `{{statusCode}}` will be replaced with the servers status code. + */ + dictResponseError: "Server responded with {{statusCode}} code.", + + /** + * If `addRemoveLinks` is true, the text to be used for the cancel upload link. + */ + dictCancelUpload: "Cancel upload", + + /** + * The text that is displayed if an upload was manually canceled + */ + dictUploadCanceled: "Upload canceled.", + + /** + * If `addRemoveLinks` is true, the text to be used for confirmation when cancelling upload. + */ + dictCancelUploadConfirmation: "Are you sure you want to cancel this upload?", + + /** + * If `addRemoveLinks` is true, the text to be used to remove a file. + */ + dictRemoveFile: "Remove file", + + /** + * If this is not null, then the user will be prompted before removing a file. + */ + dictRemoveFileConfirmation: null, + + /** + * Displayed if `maxFiles` is st and exceeded. + * The string `{{maxFiles}}` will be replaced by the configuration value. + */ + dictMaxFilesExceeded: "You can not upload any more files.", + + /** + * Allows you to translate the different units. Starting with `tb` for terabytes and going down to + * `b` for bytes. + */ + dictFileSizeUnits: { tb: "TB", gb: "GB", mb: "MB", kb: "KB", b: "b" }, + /** + * Called when dropzone initialized + * You can add event listeners here + */ + init: function init() {}, + + + /** + * Can be an **object** of additional parameters to transfer to the server, **or** a `Function` + * that gets invoked with the `files`, `xhr` and, if it's a chunked upload, `chunk` arguments. In case + * of a function, this needs to return a map. + * + * The default implementation does nothing for normal uploads, but adds relevant information for + * chunked uploads. + * + * This is the same as adding hidden input fields in the form element. + */ + params: function params(files, xhr, chunk) { + if (chunk) { + return { + dzuuid: chunk.file.upload.uuid, + dzchunkindex: chunk.index, + dztotalfilesize: chunk.file.size, + dzchunksize: this.options.chunkSize, + dztotalchunkcount: chunk.file.upload.totalChunkCount, + dzchunkbyteoffset: chunk.index * this.options.chunkSize + }; + } + }, + + + /** + * A function that gets a [file](https://developer.mozilla.org/en-US/docs/DOM/File) + * and a `done` function as parameters. + * + * If the done function is invoked without arguments, the file is "accepted" and will + * be processed. If you pass an error message, the file is rejected, and the error + * message will be displayed. + * This function will not be called if the file is too big or doesn't match the mime types. + */ + accept: function accept(file, done) { + return done(); + }, + + + /** + * The callback that will be invoked when all chunks have been uploaded for a file. + * It gets the file for which the chunks have been uploaded as the first parameter, + * and the `done` function as second. `done()` needs to be invoked when everything + * needed to finish the upload process is done. + */ + chunksUploaded: function chunksUploaded(file, done) { + done(); + }, + + /** + * Gets called when the browser is not supported. + * The default implementation shows the fallback input field and adds + * a text. + */ + fallback: function fallback() { + // This code should pass in IE7... :( + var messageElement = void 0; + this.element.className = this.element.className + " dz-browser-not-supported"; + + for (var _iterator2 = this.element.getElementsByTagName("div"), _isArray2 = true, _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { + var _ref2; + + if (_isArray2) { + if (_i2 >= _iterator2.length) break; + _ref2 = _iterator2[_i2++]; + } else { + _i2 = _iterator2.next(); + if (_i2.done) break; + _ref2 = _i2.value; + } + var child = _ref2; - /* - This is a list of all available events you can register on a dropzone object. - - You can register an event handler like this: - - dropzone.on("dragEnter", function() { }); - */ - - Dropzone.prototype.events = ["drop", "dragstart", "dragend", "dragenter", "dragover", "dragleave", "addedfile", "removedfile", "thumbnail", "error", "errormultiple", "processing", "processingmultiple", "uploadprogress", "totaluploadprogress", "sending", "sendingmultiple", "success", "successmultiple", "canceled", "canceledmultiple", "complete", "completemultiple", "reset", "maxfilesexceeded", "maxfilesreached", "queuecomplete"]; - - Dropzone.prototype.defaultOptions = { - url: null, - method: "post", - withCredentials: false, - parallelUploads: 2, - uploadMultiple: false, - maxFilesize: 256, - paramName: "file", - createImageThumbnails: true, - maxThumbnailFilesize: 10, - thumbnailWidth: 120, - thumbnailHeight: 120, - filesizeBase: 1000, - maxFiles: null, - filesizeBase: 1000, - params: {}, - clickable: true, - ignoreHiddenFiles: true, - acceptedFiles: null, - acceptedMimeTypes: null, - autoProcessQueue: true, - autoQueue: true, - addRemoveLinks: false, - previewsContainer: null, - capture: null, - dictDefaultMessage: "Drop files here to upload", - dictFallbackMessage: "Your browser does not support drag'n'drop file uploads.", - dictFallbackText: "Please use the fallback form below to upload your files like in the olden days.", - dictFileTooBig: "File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.", - dictInvalidFileType: "You can't upload files of this type.", - dictResponseError: "Server responded with {{statusCode}} code.", - dictCancelUpload: "Cancel upload", - dictCancelUploadConfirmation: "Are you sure you want to cancel this upload?", - dictRemoveFile: "Remove file", - dictRemoveFileConfirmation: null, - dictMaxFilesExceeded: "You can not upload any more files.", - accept: function(file, done) { - return done(); - }, - init: function() { - return noop; - }, - forceFallback: false, - fallback: function() { - var child, messageElement, span, _i, _len, _ref; - this.element.className = "" + this.element.className + " dz-browser-not-supported"; - _ref = this.element.getElementsByTagName("div"); - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - child = _ref[_i]; - if (/(^| )dz-message($| )/.test(child.className)) { - messageElement = child; - child.className = "dz-message"; - continue; + if (/(^| )dz-message($| )/.test(child.className)) { + messageElement = child; + child.className = "dz-message"; // Removes the 'dz-default' class + break; + } } - } - if (!messageElement) { - messageElement = Dropzone.createElement("
"); - this.element.appendChild(messageElement); - } - span = messageElement.getElementsByTagName("span")[0]; - if (span) { - span.textContent = this.options.dictFallbackMessage; - } - return this.element.appendChild(this.getFallbackForm()); - }, - resize: function(file) { - var info, srcRatio, trgRatio; - info = { - srcX: 0, - srcY: 0, - srcWidth: file.width, - srcHeight: file.height - }; - srcRatio = file.width / file.height; - info.optWidth = this.options.thumbnailWidth; - info.optHeight = this.options.thumbnailHeight; - if ((info.optWidth == null) && (info.optHeight == null)) { - info.optWidth = info.srcWidth; - info.optHeight = info.srcHeight; - } else if (info.optWidth == null) { - info.optWidth = srcRatio * info.optHeight; - } else if (info.optHeight == null) { - info.optHeight = (1 / srcRatio) * info.optWidth; - } - trgRatio = info.optWidth / info.optHeight; - if (file.height < info.optHeight || file.width < info.optWidth) { - info.trgHeight = info.srcHeight; - info.trgWidth = info.srcWidth; - } else { - if (srcRatio > trgRatio) { - info.srcHeight = file.height; - info.srcWidth = info.srcHeight * trgRatio; - } else { - info.srcWidth = file.width; - info.srcHeight = info.srcWidth / trgRatio; + if (!messageElement) { + messageElement = Dropzone.createElement("
"); + this.element.appendChild(messageElement); } - } - info.srcX = (file.width - info.srcWidth) / 2; - info.srcY = (file.height - info.srcHeight) / 2; - return info; - }, - /* - Those functions register themselves to the events on init and handle all - the user interface specific stuff. Overwriting them won't break the upload - but can break the way it's displayed. - You can overwrite them if you don't like the default behavior. If you just - want to add an additional event handler, register it on the dropzone object - and don't overwrite those options. - */ - drop: function(e) { - return this.element.classList.remove("dz-drag-hover"); - }, - dragstart: noop, - dragend: function(e) { - return this.element.classList.remove("dz-drag-hover"); - }, - dragenter: function(e) { - return this.element.classList.add("dz-drag-hover"); - }, - dragover: function(e) { - return this.element.classList.add("dz-drag-hover"); - }, - dragleave: function(e) { - return this.element.classList.remove("dz-drag-hover"); - }, - paste: noop, - reset: function() { - return this.element.classList.remove("dz-started"); - }, - addedfile: function(file) { - var node, removeFileEvent, removeLink, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _results; - if (this.element === this.previewsContainer) { - this.element.classList.add("dz-started"); - } - if (this.previewsContainer) { - file.previewElement = Dropzone.createElement(this.options.previewTemplate.trim()); - file.previewTemplate = file.previewElement; - this.previewsContainer.appendChild(file.previewElement); - _ref = file.previewElement.querySelectorAll("[data-dz-name]"); - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - node = _ref[_i]; - node.textContent = file.name; + var span = messageElement.getElementsByTagName("span")[0]; + if (span) { + if (span.textContent != null) { + span.textContent = this.options.dictFallbackMessage; + } else if (span.innerText != null) { + span.innerText = this.options.dictFallbackMessage; + } + } + + return this.element.appendChild(this.getFallbackForm()); + }, + + + /** + * Gets called to calculate the thumbnail dimensions. + * + * It gets `file`, `width` and `height` (both may be `null`) as parameters and must return an object containing: + * + * - `srcWidth` & `srcHeight` (required) + * - `trgWidth` & `trgHeight` (required) + * - `srcX` & `srcY` (optional, default `0`) + * - `trgX` & `trgY` (optional, default `0`) + * + * Those values are going to be used by `ctx.drawImage()`. + */ + resize: function resize(file, width, height, resizeMethod) { + var info = { + srcX: 0, + srcY: 0, + srcWidth: file.width, + srcHeight: file.height + }; + + var srcRatio = file.width / file.height; + + // Automatically calculate dimensions if not specified + if (width == null && height == null) { + width = info.srcWidth; + height = info.srcHeight; + } else if (width == null) { + width = height * srcRatio; + } else if (height == null) { + height = width / srcRatio; + } + + // Make sure images aren't upscaled + width = Math.min(width, info.srcWidth); + height = Math.min(height, info.srcHeight); + + var trgRatio = width / height; + + if (info.srcWidth > width || info.srcHeight > height) { + // Image is bigger and needs rescaling + if (resizeMethod === 'crop') { + if (srcRatio > trgRatio) { + info.srcHeight = file.height; + info.srcWidth = info.srcHeight * trgRatio; + } else { + info.srcWidth = file.width; + info.srcHeight = info.srcWidth / trgRatio; + } + } else if (resizeMethod === 'contain') { + // Method 'contain' + if (srcRatio > trgRatio) { + height = width / srcRatio; + } else { + width = height * srcRatio; + } + } else { + throw new Error("Unknown resizeMethod '" + resizeMethod + "'"); + } } - _ref1 = file.previewElement.querySelectorAll("[data-dz-size]"); - for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { - node = _ref1[_j]; - node.innerHTML = this.filesize(file.size); + + info.srcX = (file.width - info.srcWidth) / 2; + info.srcY = (file.height - info.srcHeight) / 2; + + info.trgWidth = width; + info.trgHeight = height; + + return info; + }, + + + /** + * Can be used to transform the file (for example, resize an image if necessary). + * + * The default implementation uses `resizeWidth` and `resizeHeight` (if provided) and resizes + * images according to those dimensions. + * + * Gets the `file` as the first parameter, and a `done()` function as the second, that needs + * to be invoked with the file when the transformation is done. + */ + transformFile: function transformFile(file, done) { + if ((this.options.resizeWidth || this.options.resizeHeight) && file.type.match(/image.*/)) { + return this.resizeImage(file, this.options.resizeWidth, this.options.resizeHeight, this.options.resizeMethod, done); + } else { + return done(file); } - if (this.options.addRemoveLinks) { - file._removeLink = Dropzone.createElement("" + this.options.dictRemoveFile + ""); - file.previewElement.appendChild(file._removeLink); + }, + + + /** + * A string that contains the template used for each dropped + * file. Change it to fulfill your needs but make sure to properly + * provide all elements. + * + * If you want to use an actual HTML element instead of providing a String + * as a config option, you could create a div with the id `tpl`, + * put the template inside it and provide the element like this: + * + * document + * .querySelector('#tpl') + * .innerHTML + * + */ + previewTemplate: "
\n
\n
\n
\n
\n
\n
\n
\n
\n \n Check\n \n \n \n \n \n
\n
\n \n Error\n \n \n \n \n \n \n \n
\n
", + + // END OPTIONS + // (Required by the dropzone documentation parser) + + + /* + Those functions register themselves to the events on init and handle all + the user interface specific stuff. Overwriting them won't break the upload + but can break the way it's displayed. + You can overwrite them if you don't like the default behavior. If you just + want to add an additional event handler, register it on the dropzone object + and don't overwrite those options. + */ + + // Those are self explanatory and simply concern the DragnDrop. + drop: function drop(e) { + return this.element.classList.remove("dz-drag-hover"); + }, + dragstart: function dragstart(e) {}, + dragend: function dragend(e) { + return this.element.classList.remove("dz-drag-hover"); + }, + dragenter: function dragenter(e) { + return this.element.classList.add("dz-drag-hover"); + }, + dragover: function dragover(e) { + return this.element.classList.add("dz-drag-hover"); + }, + dragleave: function dragleave(e) { + return this.element.classList.remove("dz-drag-hover"); + }, + paste: function paste(e) {}, + + + // Called whenever there are no files left in the dropzone anymore, and the + // dropzone should be displayed as if in the initial state. + reset: function reset() { + return this.element.classList.remove("dz-started"); + }, + + + // Called when a file is added to the queue + // Receives `file` + addedfile: function addedfile(file) { + var _this2 = this; + + if (this.element === this.previewsContainer) { + this.element.classList.add("dz-started"); } - removeFileEvent = (function(_this) { - return function(e) { + + if (this.previewsContainer) { + file.previewElement = Dropzone.createElement(this.options.previewTemplate.trim()); + file.previewTemplate = file.previewElement; // Backwards compatibility + + this.previewsContainer.appendChild(file.previewElement); + for (var _iterator3 = file.previewElement.querySelectorAll("[data-dz-name]"), _isArray3 = true, _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { + var _ref3; + + if (_isArray3) { + if (_i3 >= _iterator3.length) break; + _ref3 = _iterator3[_i3++]; + } else { + _i3 = _iterator3.next(); + if (_i3.done) break; + _ref3 = _i3.value; + } + + var node = _ref3; + + node.textContent = file.name; + } + for (var _iterator4 = file.previewElement.querySelectorAll("[data-dz-size]"), _isArray4 = true, _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { + if (_isArray4) { + if (_i4 >= _iterator4.length) break; + node = _iterator4[_i4++]; + } else { + _i4 = _iterator4.next(); + if (_i4.done) break; + node = _i4.value; + } + + node.innerHTML = this.filesize(file.size); + } + + if (this.options.addRemoveLinks) { + file._removeLink = Dropzone.createElement("" + this.options.dictRemoveFile + ""); + file.previewElement.appendChild(file._removeLink); + } + + var removeFileEvent = function removeFileEvent(e) { e.preventDefault(); e.stopPropagation(); if (file.status === Dropzone.UPLOADING) { - return Dropzone.confirm(_this.options.dictCancelUploadConfirmation, function() { - return _this.removeFile(file); + return Dropzone.confirm(_this2.options.dictCancelUploadConfirmation, function () { + return _this2.removeFile(file); }); } else { - if (_this.options.dictRemoveFileConfirmation) { - return Dropzone.confirm(_this.options.dictRemoveFileConfirmation, function() { - return _this.removeFile(file); + if (_this2.options.dictRemoveFileConfirmation) { + return Dropzone.confirm(_this2.options.dictRemoveFileConfirmation, function () { + return _this2.removeFile(file); }); } else { - return _this.removeFile(file); + return _this2.removeFile(file); } } }; - })(this); - _ref2 = file.previewElement.querySelectorAll("[data-dz-remove]"); - _results = []; - for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) { - removeLink = _ref2[_k]; - _results.push(removeLink.addEventListener("click", removeFileEvent)); - } - return _results; - } - }, - removedfile: function(file) { - var _ref; - if (file.previewElement) { - if ((_ref = file.previewElement) != null) { - _ref.parentNode.removeChild(file.previewElement); + + for (var _iterator5 = file.previewElement.querySelectorAll("[data-dz-remove]"), _isArray5 = true, _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) { + var _ref4; + + if (_isArray5) { + if (_i5 >= _iterator5.length) break; + _ref4 = _iterator5[_i5++]; + } else { + _i5 = _iterator5.next(); + if (_i5.done) break; + _ref4 = _i5.value; + } + + var removeLink = _ref4; + + removeLink.addEventListener("click", removeFileEvent); + } } - } - return this._updateMaxFilesReachedClass(); - }, - thumbnail: function(file, dataUrl) { - var thumbnailElement, _i, _len, _ref; - if (file.previewElement) { - file.previewElement.classList.remove("dz-file-preview"); - _ref = file.previewElement.querySelectorAll("[data-dz-thumbnail]"); - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - thumbnailElement = _ref[_i]; - thumbnailElement.alt = file.name; - thumbnailElement.src = dataUrl; + }, + + + // Called whenever a file is removed. + removedfile: function removedfile(file) { + if (file.previewElement != null && file.previewElement.parentNode != null) { + file.previewElement.parentNode.removeChild(file.previewElement); } - return setTimeout(((function(_this) { - return function() { + return this._updateMaxFilesReachedClass(); + }, + + + // Called when a thumbnail has been generated + // Receives `file` and `dataUrl` + thumbnail: function thumbnail(file, dataUrl) { + if (file.previewElement) { + file.previewElement.classList.remove("dz-file-preview"); + for (var _iterator6 = file.previewElement.querySelectorAll("[data-dz-thumbnail]"), _isArray6 = true, _i6 = 0, _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator]();;) { + var _ref5; + + if (_isArray6) { + if (_i6 >= _iterator6.length) break; + _ref5 = _iterator6[_i6++]; + } else { + _i6 = _iterator6.next(); + if (_i6.done) break; + _ref5 = _i6.value; + } + + var thumbnailElement = _ref5; + + thumbnailElement.alt = file.name; + thumbnailElement.src = dataUrl; + } + + return setTimeout(function () { return file.previewElement.classList.add("dz-image-preview"); - }; - })(this)), 1); - } - }, - error: function(file, message) { - var node, _i, _len, _ref, _results; - if (file.previewElement) { - file.previewElement.classList.add("dz-error"); - if (typeof message !== "String" && message.error) { - message = message.error; + }, 1); } - _ref = file.previewElement.querySelectorAll("[data-dz-errormessage]"); - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - node = _ref[_i]; - _results.push(node.textContent = message); + }, + + + // Called whenever an error occurs + // Receives `file` and `message` + error: function error(file, message) { + if (file.previewElement) { + file.previewElement.classList.add("dz-error"); + if (typeof message !== "String" && message.error) { + message = message.error; + } + for (var _iterator7 = file.previewElement.querySelectorAll("[data-dz-errormessage]"), _isArray7 = true, _i7 = 0, _iterator7 = _isArray7 ? _iterator7 : _iterator7[Symbol.iterator]();;) { + var _ref6; + + if (_isArray7) { + if (_i7 >= _iterator7.length) break; + _ref6 = _iterator7[_i7++]; + } else { + _i7 = _iterator7.next(); + if (_i7.done) break; + _ref6 = _i7.value; + } + + var node = _ref6; + + node.textContent = message; + } } - return _results; - } - }, - errormultiple: noop, - processing: function(file) { - if (file.previewElement) { - file.previewElement.classList.add("dz-processing"); - if (file._removeLink) { - return file._removeLink.textContent = this.options.dictCancelUpload; + }, + errormultiple: function errormultiple() {}, + + + // Called when a file gets processed. Since there is a cue, not all added + // files are processed immediately. + // Receives `file` + processing: function processing(file) { + if (file.previewElement) { + file.previewElement.classList.add("dz-processing"); + if (file._removeLink) { + return file._removeLink.innerHTML = this.options.dictCancelUpload; + } } - } - }, - processingmultiple: noop, - uploadprogress: function(file, progress, bytesSent) { - var node, _i, _len, _ref, _results; - if (file.previewElement) { - _ref = file.previewElement.querySelectorAll("[data-dz-uploadprogress]"); - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - node = _ref[_i]; - if (node.nodeName === 'PROGRESS') { - _results.push(node.value = progress); - } else { - _results.push(node.style.width = "" + progress + "%"); + }, + processingmultiple: function processingmultiple() {}, + + + // Called whenever the upload progress gets updated. + // Receives `file`, `progress` (percentage 0-100) and `bytesSent`. + // To get the total number of bytes of the file, use `file.size` + uploadprogress: function uploadprogress(file, progress, bytesSent) { + if (file.previewElement) { + for (var _iterator8 = file.previewElement.querySelectorAll("[data-dz-uploadprogress]"), _isArray8 = true, _i8 = 0, _iterator8 = _isArray8 ? _iterator8 : _iterator8[Symbol.iterator]();;) { + var _ref7; + + if (_isArray8) { + if (_i8 >= _iterator8.length) break; + _ref7 = _iterator8[_i8++]; + } else { + _i8 = _iterator8.next(); + if (_i8.done) break; + _ref7 = _i8.value; + } + + var node = _ref7; + + node.nodeName === 'PROGRESS' ? node.value = progress : node.style.width = progress + "%"; } } - return _results; - } - }, - totaluploadprogress: noop, - sending: noop, - sendingmultiple: noop, - success: function(file) { - if (file.previewElement) { - return file.previewElement.classList.add("dz-success"); - } - }, - successmultiple: noop, - canceled: function(file) { - return this.emit("error", file, "Upload canceled."); - }, - canceledmultiple: noop, - complete: function(file) { - if (file._removeLink) { - file._removeLink.textContent = this.options.dictRemoveFile; - } - if (file.previewElement) { - return file.previewElement.classList.add("dz-complete"); - } - }, - completemultiple: noop, - maxfilesexceeded: noop, - maxfilesreached: noop, - queuecomplete: noop, - previewTemplate: "
\n
\n
\n
\n
\n
\n
\n
\n
\n \n Check\n \n \n \n \n \n
\n
\n \n Error\n \n \n \n \n \n \n \n
\n
" - }; + }, - extend = function() { - var key, object, objects, target, val, _i, _len; - target = arguments[0], objects = 2 <= arguments.length ? __slice.call(arguments, 1) : []; - for (_i = 0, _len = objects.length; _i < _len; _i++) { - object = objects[_i]; - for (key in object) { - val = object[key]; - target[key] = val; - } + + // Called whenever the total upload progress gets updated. + // Called with totalUploadProgress (0-100), totalBytes and totalBytesSent + totaluploadprogress: function totaluploadprogress() {}, + + + // Called just before the file is sent. Gets the `xhr` object as second + // parameter, so you can modify it (for example to add a CSRF token) and a + // `formData` object to add additional information. + sending: function sending() {}, + sendingmultiple: function sendingmultiple() {}, + + + // When the complete upload is finished and successful + // Receives `file` + success: function success(file) { + if (file.previewElement) { + return file.previewElement.classList.add("dz-success"); + } + }, + successmultiple: function successmultiple() {}, + + + // When the upload is canceled. + canceled: function canceled(file) { + return this.emit("error", file, this.options.dictUploadCanceled); + }, + canceledmultiple: function canceledmultiple() {}, + + + // When the upload is finished, either with success or an error. + // Receives `file` + complete: function complete(file) { + if (file._removeLink) { + file._removeLink.innerHTML = this.options.dictRemoveFile; + } + if (file.previewElement) { + return file.previewElement.classList.add("dz-complete"); + } + }, + completemultiple: function completemultiple() {}, + maxfilesexceeded: function maxfilesexceeded() {}, + maxfilesreached: function maxfilesreached() {}, + queuecomplete: function queuecomplete() {}, + addedfiles: function addedfiles() {} + }; + + this.prototype._thumbnailQueue = []; + this.prototype._processingThumbnail = false; + } + + // global utility + + }, { + key: "extend", + value: function extend(target) { + for (var _len2 = arguments.length, objects = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { + objects[_key2 - 1] = arguments[_key2]; } - return target; - }; - function Dropzone(element, options) { - var elementOptions, fallback, _ref; - this.element = element; - this.version = Dropzone.version; - this.defaultOptions.previewTemplate = this.defaultOptions.previewTemplate.replace(/\n*/g, ""); - this.clickableElements = []; - this.listeners = []; - this.files = []; - if (typeof this.element === "string") { - this.element = document.querySelector(this.element); - } - if (!(this.element && (this.element.nodeType != null))) { - throw new Error("Invalid dropzone element."); - } - if (this.element.dropzone) { - throw new Error("Dropzone already attached."); - } - Dropzone.instances.push(this); - this.element.dropzone = this; - elementOptions = (_ref = Dropzone.optionsForElement(this.element)) != null ? _ref : {}; - this.options = extend({}, this.defaultOptions, elementOptions, options != null ? options : {}); - if (this.options.forceFallback || !Dropzone.isBrowserSupported()) { - return this.options.fallback.call(this); - } - if (this.options.url == null) { - this.options.url = this.element.getAttribute("action"); - } - if (!this.options.url) { - throw new Error("No URL provided."); - } - if (this.options.acceptedFiles && this.options.acceptedMimeTypes) { - throw new Error("You can't provide both 'acceptedFiles' and 'acceptedMimeTypes'. 'acceptedMimeTypes' is deprecated."); - } - if (this.options.acceptedMimeTypes) { - this.options.acceptedFiles = this.options.acceptedMimeTypes; - delete this.options.acceptedMimeTypes; - } - this.options.method = this.options.method.toUpperCase(); - if ((fallback = this.getExistingFallback()) && fallback.parentNode) { - fallback.parentNode.removeChild(fallback); - } - if (this.options.previewsContainer !== false) { - if (this.options.previewsContainer) { - this.previewsContainer = Dropzone.getElement(this.options.previewsContainer, "previewsContainer"); + for (var _iterator9 = objects, _isArray9 = true, _i9 = 0, _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator]();;) { + var _ref8; + + if (_isArray9) { + if (_i9 >= _iterator9.length) break; + _ref8 = _iterator9[_i9++]; } else { - this.previewsContainer = this.element; + _i9 = _iterator9.next(); + if (_i9.done) break; + _ref8 = _i9.value; } - } - if (this.options.clickable) { - if (this.options.clickable === true) { - this.clickableElements = [this.element]; - } else { - this.clickableElements = Dropzone.getElements(this.options.clickable, "clickable"); + + var object = _ref8; + + for (var key in object) { + var val = object[key]; + target[key] = val; } } - this.init(); + return target; } + }]); - Dropzone.prototype.getAcceptedFiles = function() { - var file, _i, _len, _ref, _results; - _ref = this.files; - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - file = _ref[_i]; - if (file.accepted) { - _results.push(file); - } - } - return _results; - }; + function Dropzone(el, options) { + _classCallCheck(this, Dropzone); - Dropzone.prototype.getRejectedFiles = function() { - var file, _i, _len, _ref, _results; - _ref = this.files; - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - file = _ref[_i]; - if (!file.accepted) { - _results.push(file); - } + var _this = _possibleConstructorReturn(this, (Dropzone.__proto__ || Object.getPrototypeOf(Dropzone)).call(this)); + + var fallback = void 0, + left = void 0; + _this.element = el; + // For backwards compatibility since the version was in the prototype previously + _this.version = Dropzone.version; + + _this.defaultOptions.previewTemplate = _this.defaultOptions.previewTemplate.replace(/\n*/g, ""); + + _this.clickableElements = []; + _this.listeners = []; + _this.files = []; // All files + + if (typeof _this.element === "string") { + _this.element = document.querySelector(_this.element); + } + + // Not checking if instance of HTMLElement or Element since IE9 is extremely weird. + if (!_this.element || _this.element.nodeType == null) { + throw new Error("Invalid dropzone element."); + } + + if (_this.element.dropzone) { + throw new Error("Dropzone already attached."); + } + + // Now add this dropzone to the instances. + Dropzone.instances.push(_this); + + // Put the dropzone inside the element itself. + _this.element.dropzone = _this; + + var elementOptions = (left = Dropzone.optionsForElement(_this.element)) != null ? left : {}; + + _this.options = Dropzone.extend({}, _this.defaultOptions, elementOptions, options != null ? options : {}); + + // If the browser failed, just call the fallback and leave + if (_this.options.forceFallback || !Dropzone.isBrowserSupported()) { + var _ret; + + return _ret = _this.options.fallback.call(_this), _possibleConstructorReturn(_this, _ret); + } + + // @options.url = @element.getAttribute "action" unless @options.url? + if (_this.options.url == null) { + _this.options.url = _this.element.getAttribute("action"); + } + + if (!_this.options.url) { + throw new Error("No URL provided."); + } + + if (_this.options.acceptedFiles && _this.options.acceptedMimeTypes) { + throw new Error("You can't provide both 'acceptedFiles' and 'acceptedMimeTypes'. 'acceptedMimeTypes' is deprecated."); + } + + if (_this.options.uploadMultiple && _this.options.chunking) { + throw new Error('You cannot set both: uploadMultiple and chunking.'); + } + + // Backwards compatibility + if (_this.options.acceptedMimeTypes) { + _this.options.acceptedFiles = _this.options.acceptedMimeTypes; + delete _this.options.acceptedMimeTypes; + } + + // Backwards compatibility + if (_this.options.renameFilename != null) { + _this.options.renameFile = function (file) { + return _this.options.renameFilename.call(_this, file.name, file); + }; + } + + _this.options.method = _this.options.method.toUpperCase(); + + if ((fallback = _this.getExistingFallback()) && fallback.parentNode) { + // Remove the fallback + fallback.parentNode.removeChild(fallback); + } + + // Display previews in the previewsContainer element or the Dropzone element unless explicitly set to false + if (_this.options.previewsContainer !== false) { + if (_this.options.previewsContainer) { + _this.previewsContainer = Dropzone.getElement(_this.options.previewsContainer, "previewsContainer"); + } else { + _this.previewsContainer = _this.element; } - return _results; - }; + } - Dropzone.prototype.getFilesWithStatus = function(status) { - var file, _i, _len, _ref, _results; - _ref = this.files; - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - file = _ref[_i]; - if (file.status === status) { - _results.push(file); - } + if (_this.options.clickable) { + if (_this.options.clickable === true) { + _this.clickableElements = [_this.element]; + } else { + _this.clickableElements = Dropzone.getElements(_this.options.clickable, "clickable"); } - return _results; - }; + } - Dropzone.prototype.getQueuedFiles = function() { - return this.getFilesWithStatus(Dropzone.QUEUED); - }; + _this.init(); + return _this; + } + + // Returns all files that have been accepted + + + _createClass(Dropzone, [{ + key: "getAcceptedFiles", + value: function getAcceptedFiles() { + return this.files.filter(function (file) { + return file.accepted; + }).map(function (file) { + return file; + }); + } + + // Returns all files that have been rejected + // Not sure when that's going to be useful, but added for completeness. - Dropzone.prototype.getUploadingFiles = function() { + }, { + key: "getRejectedFiles", + value: function getRejectedFiles() { + return this.files.filter(function (file) { + return !file.accepted; + }).map(function (file) { + return file; + }); + } + }, { + key: "getFilesWithStatus", + value: function getFilesWithStatus(status) { + return this.files.filter(function (file) { + return file.status === status; + }).map(function (file) { + return file; + }); + } + + // Returns all files that are in the queue + + }, { + key: "getQueuedFiles", + value: function getQueuedFiles() { + return this.getFilesWithStatus(Dropzone.QUEUED); + } + }, { + key: "getUploadingFiles", + value: function getUploadingFiles() { return this.getFilesWithStatus(Dropzone.UPLOADING); - }; + } + }, { + key: "getAddedFiles", + value: function getAddedFiles() { + return this.getFilesWithStatus(Dropzone.ADDED); + } - Dropzone.prototype.getActiveFiles = function() { - var file, _i, _len, _ref, _results; - _ref = this.files; - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - file = _ref[_i]; - if (file.status === Dropzone.UPLOADING || file.status === Dropzone.QUEUED) { - _results.push(file); - } - } - return _results; - }; + // Files that are either queued or uploading + + }, { + key: "getActiveFiles", + value: function getActiveFiles() { + return this.files.filter(function (file) { + return file.status === Dropzone.UPLOADING || file.status === Dropzone.QUEUED; + }).map(function (file) { + return file; + }); + } + + // The function that gets called when Dropzone is initialized. You + // can (and should) setup event listeners inside this function. - Dropzone.prototype.init = function() { - var eventName, noPropagation, setupHiddenFileInput, _i, _len, _ref, _ref1; + }, { + key: "init", + value: function init() { + var _this3 = this; + + // In case it isn't set already if (this.element.tagName === "form") { this.element.setAttribute("enctype", "multipart/form-data"); } + if (this.element.classList.contains("dropzone") && !this.element.querySelector(".dz-message")) { this.element.appendChild(Dropzone.createElement("
" + this.options.dictDefaultMessage + "
")); } + if (this.clickableElements.length) { - setupHiddenFileInput = (function(_this) { - return function() { - if (_this.hiddenFileInput) { - document.body.removeChild(_this.hiddenFileInput); - } - _this.hiddenFileInput = document.createElement("input"); - _this.hiddenFileInput.setAttribute("type", "file"); - if ((_this.options.maxFiles == null) || _this.options.maxFiles > 1) { - _this.hiddenFileInput.setAttribute("multiple", "multiple"); - } - _this.hiddenFileInput.className = "dz-hidden-input"; - if (_this.options.acceptedFiles != null) { - _this.hiddenFileInput.setAttribute("accept", _this.options.acceptedFiles); - } - if (_this.options.capture != null) { - _this.hiddenFileInput.setAttribute("capture", _this.options.capture); - } - _this.hiddenFileInput.style.visibility = "hidden"; - _this.hiddenFileInput.style.position = "absolute"; - _this.hiddenFileInput.style.top = "0"; - _this.hiddenFileInput.style.left = "0"; - _this.hiddenFileInput.style.height = "0"; - _this.hiddenFileInput.style.width = "0"; - document.body.appendChild(_this.hiddenFileInput); - return _this.hiddenFileInput.addEventListener("change", function() { - var file, files, _i, _len; - files = _this.hiddenFileInput.files; - if (files.length) { - for (_i = 0, _len = files.length; _i < _len; _i++) { - file = files[_i]; - _this.addFile(file); + var setupHiddenFileInput = function setupHiddenFileInput() { + if (_this3.hiddenFileInput) { + _this3.hiddenFileInput.parentNode.removeChild(_this3.hiddenFileInput); + } + _this3.hiddenFileInput = document.createElement("input"); + _this3.hiddenFileInput.setAttribute("type", "file"); + if (_this3.options.maxFiles === null || _this3.options.maxFiles > 1) { + _this3.hiddenFileInput.setAttribute("multiple", "multiple"); + } + _this3.hiddenFileInput.className = "dz-hidden-input"; + + if (_this3.options.acceptedFiles !== null) { + _this3.hiddenFileInput.setAttribute("accept", _this3.options.acceptedFiles); + } + if (_this3.options.capture !== null) { + _this3.hiddenFileInput.setAttribute("capture", _this3.options.capture); + } + + // Not setting `display="none"` because some browsers don't accept clicks + // on elements that aren't displayed. + _this3.hiddenFileInput.style.visibility = "hidden"; + _this3.hiddenFileInput.style.position = "absolute"; + _this3.hiddenFileInput.style.top = "0"; + _this3.hiddenFileInput.style.left = "0"; + _this3.hiddenFileInput.style.height = "0"; + _this3.hiddenFileInput.style.width = "0"; + Dropzone.getElement(_this3.options.hiddenInputContainer, 'hiddenInputContainer').appendChild(_this3.hiddenFileInput); + return _this3.hiddenFileInput.addEventListener("change", function () { + var files = _this3.hiddenFileInput.files; + + if (files.length) { + for (var _iterator10 = files, _isArray10 = true, _i10 = 0, _iterator10 = _isArray10 ? _iterator10 : _iterator10[Symbol.iterator]();;) { + var _ref9; + + if (_isArray10) { + if (_i10 >= _iterator10.length) break; + _ref9 = _iterator10[_i10++]; + } else { + _i10 = _iterator10.next(); + if (_i10.done) break; + _ref9 = _i10.value; } + + var file = _ref9; + + _this3.addFile(file); } - return setupHiddenFileInput(); - }); - }; - })(this); + } + _this3.emit("addedfiles", files); + return setupHiddenFileInput(); + }); + }; setupHiddenFileInput(); } - this.URL = (_ref = window.URL) != null ? _ref : window.webkitURL; - _ref1 = this.events; - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - eventName = _ref1[_i]; + + this.URL = window.URL !== null ? window.URL : window.webkitURL; + + // Setup all event listeners on the Dropzone object itself. + // They're not in @setupEventListeners() because they shouldn't be removed + // again when the dropzone gets disabled. + for (var _iterator11 = this.events, _isArray11 = true, _i11 = 0, _iterator11 = _isArray11 ? _iterator11 : _iterator11[Symbol.iterator]();;) { + var _ref10; + + if (_isArray11) { + if (_i11 >= _iterator11.length) break; + _ref10 = _iterator11[_i11++]; + } else { + _i11 = _iterator11.next(); + if (_i11.done) break; + _ref10 = _i11.value; + } + + var eventName = _ref10; + this.on(eventName, this.options[eventName]); } - this.on("uploadprogress", (function(_this) { - return function() { - return _this.updateTotalUploadProgress(); - }; - })(this)); - this.on("removedfile", (function(_this) { - return function() { - return _this.updateTotalUploadProgress(); - }; - })(this)); - this.on("canceled", (function(_this) { - return function(file) { - return _this.emit("complete", file); - }; - })(this)); - this.on("complete", (function(_this) { - return function(file) { - if (_this.getUploadingFiles().length === 0 && _this.getQueuedFiles().length === 0) { - return setTimeout((function() { - return _this.emit("queuecomplete"); - }), 0); - } - }; - })(this)); - noPropagation = function(e) { + + this.on("uploadprogress", function () { + return _this3.updateTotalUploadProgress(); + }); + + this.on("removedfile", function () { + return _this3.updateTotalUploadProgress(); + }); + + this.on("canceled", function (file) { + return _this3.emit("complete", file); + }); + + // Emit a `queuecomplete` event if all files finished uploading. + this.on("complete", function (file) { + if (_this3.getAddedFiles().length === 0 && _this3.getUploadingFiles().length === 0 && _this3.getQueuedFiles().length === 0) { + // This needs to be deferred so that `queuecomplete` really triggers after `complete` + return setTimeout(function () { + return _this3.emit("queuecomplete"); + }, 0); + } + }); + + var noPropagation = function noPropagation(e) { e.stopPropagation(); if (e.preventDefault) { return e.preventDefault(); @@ -607,90 +1309,106 @@ return e.returnValue = false; } }; - this.listeners = [ - { - element: this.element, - events: { - "dragstart": (function(_this) { - return function(e) { - return _this.emit("dragstart", e); - }; - })(this), - "dragenter": (function(_this) { - return function(e) { - noPropagation(e); - return _this.emit("dragenter", e); - }; - })(this), - "dragover": (function(_this) { - return function(e) { - var efct; - try { - efct = e.dataTransfer.effectAllowed; - } catch (_error) {} - e.dataTransfer.dropEffect = 'move' === efct || 'linkMove' === efct ? 'move' : 'copy'; - noPropagation(e); - return _this.emit("dragover", e); - }; - })(this), - "dragleave": (function(_this) { - return function(e) { - return _this.emit("dragleave", e); - }; - })(this), - "drop": (function(_this) { - return function(e) { - noPropagation(e); - return _this.drop(e); - }; - })(this), - "dragend": (function(_this) { - return function(e) { - return _this.emit("dragend", e); - }; - })(this) + + // Create the listeners + this.listeners = [{ + element: this.element, + events: { + "dragstart": function dragstart(e) { + return _this3.emit("dragstart", e); + }, + "dragenter": function dragenter(e) { + noPropagation(e); + return _this3.emit("dragenter", e); + }, + "dragover": function dragover(e) { + // Makes it possible to drag files from chrome's download bar + // http://stackoverflow.com/questions/19526430/drag-and-drop-file-uploads-from-chrome-downloads-bar + // Try is required to prevent bug in Internet Explorer 11 (SCRIPT65535 exception) + var efct = void 0; + try { + efct = e.dataTransfer.effectAllowed; + } catch (error) {} + e.dataTransfer.dropEffect = 'move' === efct || 'linkMove' === efct ? 'move' : 'copy'; + + noPropagation(e); + return _this3.emit("dragover", e); + }, + "dragleave": function dragleave(e) { + return _this3.emit("dragleave", e); + }, + "drop": function drop(e) { + noPropagation(e); + return _this3.drop(e); + }, + "dragend": function dragend(e) { + return _this3.emit("dragend", e); } - } - ]; - this.clickableElements.forEach((function(_this) { - return function(clickableElement) { - return _this.listeners.push({ - element: clickableElement, - events: { - "click": function(evt) { - if ((clickableElement !== _this.element) || (evt.target === _this.element || Dropzone.elementInside(evt.target, _this.element.querySelector(".dz-message")))) { - return _this.hiddenFileInput.click(); - } + + // This is disabled right now, because the browsers don't implement it properly. + // "paste": (e) => + // noPropagation e + // @paste e + } }]; + + this.clickableElements.forEach(function (clickableElement) { + return _this3.listeners.push({ + element: clickableElement, + events: { + "click": function click(evt) { + // Only the actual dropzone or the message element should trigger file selection + if (clickableElement !== _this3.element || evt.target === _this3.element || Dropzone.elementInside(evt.target, _this3.element.querySelector(".dz-message"))) { + _this3.hiddenFileInput.click(); // Forward the click } + return true; } - }); - }; - })(this)); + } + }); + }); + this.enable(); + return this.options.init.call(this); - }; + } + + // Not fully tested yet - Dropzone.prototype.destroy = function() { - var _ref; + }, { + key: "destroy", + value: function destroy() { this.disable(); this.removeAllFiles(true); - if ((_ref = this.hiddenFileInput) != null ? _ref.parentNode : void 0) { + if (this.hiddenFileInput != null ? this.hiddenFileInput.parentNode : undefined) { this.hiddenFileInput.parentNode.removeChild(this.hiddenFileInput); this.hiddenFileInput = null; } delete this.element.dropzone; return Dropzone.instances.splice(Dropzone.instances.indexOf(this), 1); - }; + } + }, { + key: "updateTotalUploadProgress", + value: function updateTotalUploadProgress() { + var totalUploadProgress = void 0; + var totalBytesSent = 0; + var totalBytes = 0; + + var activeFiles = this.getActiveFiles(); - Dropzone.prototype.updateTotalUploadProgress = function() { - var activeFiles, file, totalBytes, totalBytesSent, totalUploadProgress, _i, _len, _ref; - totalBytesSent = 0; - totalBytes = 0; - activeFiles = this.getActiveFiles(); if (activeFiles.length) { - _ref = this.getActiveFiles(); - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - file = _ref[_i]; + for (var _iterator12 = this.getActiveFiles(), _isArray12 = true, _i12 = 0, _iterator12 = _isArray12 ? _iterator12 : _iterator12[Symbol.iterator]();;) { + var _ref11; + + if (_isArray12) { + if (_i12 >= _iterator12.length) break; + _ref11 = _iterator12[_i12++]; + } else { + _i12 = _iterator12.next(); + if (_i12.done) break; + _ref11 = _i12.value; + } + + var file = _ref11; + totalBytesSent += file.upload.bytesSent; totalBytes += file.upload.total; } @@ -698,139 +1416,200 @@ } else { totalUploadProgress = 100; } + return this.emit("totaluploadprogress", totalUploadProgress, totalBytes, totalBytesSent); - }; + } + + // @options.paramName can be a function taking one parameter rather than a string. + // A parameter name for a file is obtained simply by calling this with an index number. - Dropzone.prototype._getParamName = function(n) { + }, { + key: "_getParamName", + value: function _getParamName(n) { if (typeof this.options.paramName === "function") { return this.options.paramName(n); } else { return "" + this.options.paramName + (this.options.uploadMultiple ? "[" + n + "]" : ""); } - }; + } + + // If @options.renameFile is a function, + // the function will be used to rename the file.name before appending it to the formData + + }, { + key: "_renameFile", + value: function _renameFile(file) { + if (typeof this.options.renameFile !== "function") { + return file.name; + } + return this.options.renameFile(file); + } - Dropzone.prototype.getFallbackForm = function() { - var existingFallback, fields, fieldsString, form; + // Returns a form that can be used as fallback if the browser does not support DragnDrop + // + // If the dropzone is already a form, only the input field and button are returned. Otherwise a complete form element is provided. + // This code has to pass in IE7 :( + + }, { + key: "getFallbackForm", + value: function getFallbackForm() { + var existingFallback = void 0, + form = void 0; if (existingFallback = this.getExistingFallback()) { return existingFallback; } - fieldsString = "
"; + + var fieldsString = "
"; if (this.options.dictFallbackText) { fieldsString += "

" + this.options.dictFallbackText + "

"; } - fieldsString += "
"; - fields = Dropzone.createElement(fieldsString); + fieldsString += "
"; + + var fields = Dropzone.createElement(fieldsString); if (this.element.tagName !== "FORM") { form = Dropzone.createElement("
"); form.appendChild(fields); } else { + // Make sure that the enctype and method attributes are set properly this.element.setAttribute("enctype", "multipart/form-data"); this.element.setAttribute("method", this.options.method); } return form != null ? form : fields; - }; + } + + // Returns the fallback elements if they exist already + // + // This code has to pass in IE7 :( + + }, { + key: "getExistingFallback", + value: function getExistingFallback() { + var getFallback = function getFallback(elements) { + for (var _iterator13 = elements, _isArray13 = true, _i13 = 0, _iterator13 = _isArray13 ? _iterator13 : _iterator13[Symbol.iterator]();;) { + var _ref12; + + if (_isArray13) { + if (_i13 >= _iterator13.length) break; + _ref12 = _iterator13[_i13++]; + } else { + _i13 = _iterator13.next(); + if (_i13.done) break; + _ref12 = _i13.value; + } + + var el = _ref12; - Dropzone.prototype.getExistingFallback = function() { - var fallback, getFallback, tagName, _i, _len, _ref; - getFallback = function(elements) { - var el, _i, _len; - for (_i = 0, _len = elements.length; _i < _len; _i++) { - el = elements[_i]; if (/(^| )fallback($| )/.test(el.className)) { return el; } } }; - _ref = ["div", "form"]; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - tagName = _ref[_i]; + + var _arr = ["div", "form"]; + for (var _i14 = 0; _i14 < _arr.length; _i14++) { + var tagName = _arr[_i14]; + var fallback; if (fallback = getFallback(this.element.getElementsByTagName(tagName))) { return fallback; } } - }; + } - Dropzone.prototype.setupEventListeners = function() { - var elementListeners, event, listener, _i, _len, _ref, _results; - _ref = this.listeners; - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - elementListeners = _ref[_i]; - _results.push((function() { - var _ref1, _results1; - _ref1 = elementListeners.events; - _results1 = []; - for (event in _ref1) { - listener = _ref1[event]; - _results1.push(elementListeners.element.addEventListener(event, listener, false)); + // Activates all listeners stored in @listeners + + }, { + key: "setupEventListeners", + value: function setupEventListeners() { + return this.listeners.map(function (elementListeners) { + return function () { + var result = []; + for (var event in elementListeners.events) { + var listener = elementListeners.events[event]; + result.push(elementListeners.element.addEventListener(event, listener, false)); } - return _results1; - })()); - } - return _results; - }; + return result; + }(); + }); + } - Dropzone.prototype.removeEventListeners = function() { - var elementListeners, event, listener, _i, _len, _ref, _results; - _ref = this.listeners; - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - elementListeners = _ref[_i]; - _results.push((function() { - var _ref1, _results1; - _ref1 = elementListeners.events; - _results1 = []; - for (event in _ref1) { - listener = _ref1[event]; - _results1.push(elementListeners.element.removeEventListener(event, listener, false)); + // Deactivates all listeners stored in @listeners + + }, { + key: "removeEventListeners", + value: function removeEventListeners() { + return this.listeners.map(function (elementListeners) { + return function () { + var result = []; + for (var event in elementListeners.events) { + var listener = elementListeners.events[event]; + result.push(elementListeners.element.removeEventListener(event, listener, false)); } - return _results1; - })()); - } - return _results; - }; + return result; + }(); + }); + } + + // Removes all event listeners and cancels all files in the queue or being processed. + + }, { + key: "disable", + value: function disable() { + var _this4 = this; - Dropzone.prototype.disable = function() { - var file, _i, _len, _ref, _results; - this.clickableElements.forEach(function(element) { + this.clickableElements.forEach(function (element) { return element.classList.remove("dz-clickable"); }); this.removeEventListeners(); - _ref = this.files; - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - file = _ref[_i]; - _results.push(this.cancelUpload(file)); - } - return _results; - }; + this.disabled = true; - Dropzone.prototype.enable = function() { - this.clickableElements.forEach(function(element) { + return this.files.map(function (file) { + return _this4.cancelUpload(file); + }); + } + }, { + key: "enable", + value: function enable() { + delete this.disabled; + this.clickableElements.forEach(function (element) { return element.classList.add("dz-clickable"); }); return this.setupEventListeners(); - }; + } - Dropzone.prototype.filesize = function(size) { - var cutoff, i, selectedSize, selectedUnit, unit, units, _i, _len; - units = ['TB', 'GB', 'MB', 'KB', 'b']; - selectedSize = selectedUnit = null; - for (i = _i = 0, _len = units.length; _i < _len; i = ++_i) { - unit = units[i]; - cutoff = Math.pow(this.options.filesizeBase, 4 - i) / 10; - if (size >= cutoff) { - selectedSize = size / Math.pow(this.options.filesizeBase, 4 - i); - selectedUnit = unit; - break; + // Returns a nicely formatted filesize + + }, { + key: "filesize", + value: function filesize(size) { + var selectedSize = 0; + var selectedUnit = "b"; + + if (size > 0) { + var units = ['tb', 'gb', 'mb', 'kb', 'b']; + + for (var i = 0; i < units.length; i++) { + var unit = units[i]; + var cutoff = Math.pow(this.options.filesizeBase, 4 - i) / 10; + + if (size >= cutoff) { + selectedSize = size / Math.pow(this.options.filesizeBase, 4 - i); + selectedUnit = unit; + break; + } } + + selectedSize = Math.round(10 * selectedSize) / 10; // Cutting of digits } - selectedSize = Math.round(10 * selectedSize) / 10; - return "" + selectedSize + " " + selectedUnit; - }; - Dropzone.prototype._updateMaxFilesReachedClass = function() { - if ((this.options.maxFiles != null) && this.getAcceptedFiles().length >= this.options.maxFiles) { + return "" + selectedSize + " " + this.options.dictFileSizeUnits[selectedUnit]; + } + + // Adds or removes the `dz-max-files-reached` class from the form. + + }, { + key: "_updateMaxFilesReachedClass", + value: function _updateMaxFilesReachedClass() { + if (this.options.maxFiles != null && this.getAcceptedFiles().length >= this.options.maxFiles) { if (this.getAcceptedFiles().length === this.options.maxFiles) { this.emit('maxfilesreached', this.files); } @@ -838,519 +1617,1195 @@ } else { return this.element.classList.remove("dz-max-files-reached"); } - }; - - Dropzone.prototype.drop = function(e) { - var files, items; + } + }, { + key: "drop", + value: function drop(e) { if (!e.dataTransfer) { return; } this.emit("drop", e); - files = e.dataTransfer.files; + + // Convert the FileList to an Array + // This is necessary for IE11 + var files = []; + for (var i = 0; i < e.dataTransfer.files.length; i++) { + files[i] = e.dataTransfer.files[i]; + } + + this.emit("addedfiles", files); + + // Even if it's a folder, files.length will contain the folders. if (files.length) { - items = e.dataTransfer.items; - if (items && items.length && (items[0].webkitGetAsEntry != null)) { + var items = e.dataTransfer.items; + + if (items && items.length && items[0].webkitGetAsEntry != null) { + // The browser supports dropping of folders, so handle items instead of files this._addFilesFromItems(items); } else { this.handleFiles(files); } } - }; - - Dropzone.prototype.paste = function(e) { - var items, _ref; - if ((e != null ? (_ref = e.clipboardData) != null ? _ref.items : void 0 : void 0) == null) { + } + }, { + key: "paste", + value: function paste(e) { + if (__guard__(e != null ? e.clipboardData : undefined, function (x) { + return x.items; + }) == null) { return; } + this.emit("paste", e); - items = e.clipboardData.items; + var items = e.clipboardData.items; + + if (items.length) { return this._addFilesFromItems(items); } - }; + } + }, { + key: "handleFiles", + value: function handleFiles(files) { + for (var _iterator14 = files, _isArray14 = true, _i15 = 0, _iterator14 = _isArray14 ? _iterator14 : _iterator14[Symbol.iterator]();;) { + var _ref13; + + if (_isArray14) { + if (_i15 >= _iterator14.length) break; + _ref13 = _iterator14[_i15++]; + } else { + _i15 = _iterator14.next(); + if (_i15.done) break; + _ref13 = _i15.value; + } + + var file = _ref13; - Dropzone.prototype.handleFiles = function(files) { - var file, _i, _len, _results; - _results = []; - for (_i = 0, _len = files.length; _i < _len; _i++) { - file = files[_i]; - _results.push(this.addFile(file)); + this.addFile(file); } - return _results; - }; + } + + // When a folder is dropped (or files are pasted), items must be handled + // instead of files. + + }, { + key: "_addFilesFromItems", + value: function _addFilesFromItems(items) { + var _this5 = this; - Dropzone.prototype._addFilesFromItems = function(items) { - var entry, item, _i, _len, _results; - _results = []; - for (_i = 0, _len = items.length; _i < _len; _i++) { - item = items[_i]; - if ((item.webkitGetAsEntry != null) && (entry = item.webkitGetAsEntry())) { - if (entry.isFile) { - _results.push(this.addFile(item.getAsFile())); - } else if (entry.isDirectory) { - _results.push(this._addFilesFromDirectory(entry, entry.name)); + return function () { + var result = []; + for (var _iterator15 = items, _isArray15 = true, _i16 = 0, _iterator15 = _isArray15 ? _iterator15 : _iterator15[Symbol.iterator]();;) { + var _ref14; + + if (_isArray15) { + if (_i16 >= _iterator15.length) break; + _ref14 = _iterator15[_i16++]; } else { - _results.push(void 0); + _i16 = _iterator15.next(); + if (_i16.done) break; + _ref14 = _i16.value; } - } else if (item.getAsFile != null) { - if ((item.kind == null) || item.kind === "file") { - _results.push(this.addFile(item.getAsFile())); + + var item = _ref14; + + var entry; + if (item.webkitGetAsEntry != null && (entry = item.webkitGetAsEntry())) { + if (entry.isFile) { + result.push(_this5.addFile(item.getAsFile())); + } else if (entry.isDirectory) { + // Append all files from that directory to files + result.push(_this5._addFilesFromDirectory(entry, entry.name)); + } else { + result.push(undefined); + } + } else if (item.getAsFile != null) { + if (item.kind == null || item.kind === "file") { + result.push(_this5.addFile(item.getAsFile())); + } else { + result.push(undefined); + } } else { - _results.push(void 0); + result.push(undefined); } - } else { - _results.push(void 0); } - } - return _results; - }; + return result; + }(); + } - Dropzone.prototype._addFilesFromDirectory = function(directory, path) { - var dirReader, entriesReader; - dirReader = directory.createReader(); - entriesReader = (function(_this) { - return function(entries) { - var entry, _i, _len; - for (_i = 0, _len = entries.length; _i < _len; _i++) { - entry = entries[_i]; - if (entry.isFile) { - entry.file(function(file) { - if (_this.options.ignoreHiddenFiles && file.name.substring(0, 1) === '.') { - return; - } - file.fullPath = "" + path + "/" + file.name; - return _this.addFile(file); - }); - } else if (entry.isDirectory) { - _this._addFilesFromDirectory(entry, "" + path + "/" + entry.name); + // Goes through the directory, and adds each file it finds recursively + + }, { + key: "_addFilesFromDirectory", + value: function _addFilesFromDirectory(directory, path) { + var _this6 = this; + + var dirReader = directory.createReader(); + + var errorHandler = function errorHandler(error) { + return __guardMethod__(console, 'log', function (o) { + return o.log(error); + }); + }; + + var readEntries = function readEntries() { + return dirReader.readEntries(function (entries) { + if (entries.length > 0) { + for (var _iterator16 = entries, _isArray16 = true, _i17 = 0, _iterator16 = _isArray16 ? _iterator16 : _iterator16[Symbol.iterator]();;) { + var _ref15; + + if (_isArray16) { + if (_i17 >= _iterator16.length) break; + _ref15 = _iterator16[_i17++]; + } else { + _i17 = _iterator16.next(); + if (_i17.done) break; + _ref15 = _i17.value; + } + + var entry = _ref15; + + if (entry.isFile) { + entry.file(function (file) { + if (_this6.options.ignoreHiddenFiles && file.name.substring(0, 1) === '.') { + return; + } + file.fullPath = path + "/" + file.name; + return _this6.addFile(file); + }); + } else if (entry.isDirectory) { + _this6._addFilesFromDirectory(entry, path + "/" + entry.name); + } } + + // Recursively call readEntries() again, since browser only handle + // the first 100 entries. + // See: https://developer.mozilla.org/en-US/docs/Web/API/DirectoryReader#readEntries + readEntries(); } - }; - })(this); - return dirReader.readEntries(entriesReader, function(error) { - return typeof console !== "undefined" && console !== null ? typeof console.log === "function" ? console.log(error) : void 0 : void 0; - }); - }; + return null; + }, errorHandler); + }; + + return readEntries(); + } - Dropzone.prototype.accept = function(file, done) { - if (file.size > this.options.maxFilesize * 1024 * 1024) { + // If `done()` is called without argument the file is accepted + // If you call it with an error message, the file is rejected + // (This allows for asynchronous validation) + // + // This function checks the filesize, and if the file.type passes the + // `acceptedFiles` check. + + }, { + key: "accept", + value: function accept(file, done) { + if (this.options.maxFilesize && file.size > this.options.maxFilesize * 1024 * 1024) { return done(this.options.dictFileTooBig.replace("{{filesize}}", Math.round(file.size / 1024 / 10.24) / 100).replace("{{maxFilesize}}", this.options.maxFilesize)); } else if (!Dropzone.isValidFile(file, this.options.acceptedFiles)) { return done(this.options.dictInvalidFileType); - } else if ((this.options.maxFiles != null) && this.getAcceptedFiles().length >= this.options.maxFiles) { + } else if (this.options.maxFiles != null && this.getAcceptedFiles().length >= this.options.maxFiles) { done(this.options.dictMaxFilesExceeded.replace("{{maxFiles}}", this.options.maxFiles)); return this.emit("maxfilesexceeded", file); } else { return this.options.accept.call(this, file, done); } - }; + } + + }, { + key: "addFile", + value: function addFile(file) { + var _this7 = this; - Dropzone.prototype.addFile = function(file) { file.upload = { + uuid: Dropzone.uuidv4(), progress: 0, + // Setting the total upload size to file.size for the beginning + // It's actual different than the size to be transmitted. total: file.size, - bytesSent: 0 + bytesSent: 0, + filename: this._renameFile(file), + chunked: this.options.chunking && (this.options.forceChunking || file.size > this.options.chunkSize), + totalChunkCount: Math.ceil(file.size / this.options.chunkSize) }; this.files.push(file); + file.status = Dropzone.ADDED; + this.emit("addedfile", file); + this._enqueueThumbnail(file); - return this.accept(file, (function(_this) { - return function(error) { - if (error) { - file.accepted = false; - _this._errorProcessing([file], error); - } else { - file.accepted = true; - if (_this.options.autoQueue) { - _this.enqueueFile(file); - } - } - return _this._updateMaxFilesReachedClass(); - }; - })(this)); - }; - Dropzone.prototype.enqueueFiles = function(files) { - var file, _i, _len; - for (_i = 0, _len = files.length; _i < _len; _i++) { - file = files[_i]; + return this.accept(file, function (error) { + if (error) { + file.accepted = false; + _this7._errorProcessing([file], error); // Will set the file.status + } else { + file.accepted = true; + if (_this7.options.autoQueue) { + _this7.enqueueFile(file); + } // Will set .accepted = true + } + return _this7._updateMaxFilesReachedClass(); + }); + } + + // Wrapper for enqueueFile + + }, { + key: "enqueueFiles", + value: function enqueueFiles(files) { + for (var _iterator17 = files, _isArray17 = true, _i18 = 0, _iterator17 = _isArray17 ? _iterator17 : _iterator17[Symbol.iterator]();;) { + var _ref16; + + if (_isArray17) { + if (_i18 >= _iterator17.length) break; + _ref16 = _iterator17[_i18++]; + } else { + _i18 = _iterator17.next(); + if (_i18.done) break; + _ref16 = _i18.value; + } + + var file = _ref16; + this.enqueueFile(file); } return null; - }; + } + }, { + key: "enqueueFile", + value: function enqueueFile(file) { + var _this8 = this; - Dropzone.prototype.enqueueFile = function(file) { if (file.status === Dropzone.ADDED && file.accepted === true) { file.status = Dropzone.QUEUED; if (this.options.autoProcessQueue) { - return setTimeout(((function(_this) { - return function() { - return _this.processQueue(); - }; - })(this)), 0); + return setTimeout(function () { + return _this8.processQueue(); + }, 0); // Deferring the call } } else { throw new Error("This file can't be queued because it has already been processed or was rejected."); } - }; - - Dropzone.prototype._thumbnailQueue = []; - - Dropzone.prototype._processingThumbnail = false; + } + }, { + key: "_enqueueThumbnail", + value: function _enqueueThumbnail(file) { + var _this9 = this; - Dropzone.prototype._enqueueThumbnail = function(file) { if (this.options.createImageThumbnails && file.type.match(/image.*/) && file.size <= this.options.maxThumbnailFilesize * 1024 * 1024) { this._thumbnailQueue.push(file); - return setTimeout(((function(_this) { - return function() { - return _this._processThumbnailQueue(); - }; - })(this)), 0); + return setTimeout(function () { + return _this9._processThumbnailQueue(); + }, 0); // Deferring the call } - }; + } + }, { + key: "_processThumbnailQueue", + value: function _processThumbnailQueue() { + var _this10 = this; - Dropzone.prototype._processThumbnailQueue = function() { if (this._processingThumbnail || this._thumbnailQueue.length === 0) { return; } + this._processingThumbnail = true; - return this.createThumbnail(this._thumbnailQueue.shift(), (function(_this) { - return function() { - _this._processingThumbnail = false; - return _this._processThumbnailQueue(); - }; - })(this)); - }; + var file = this._thumbnailQueue.shift(); + return this.createThumbnail(file, this.options.thumbnailWidth, this.options.thumbnailHeight, this.options.thumbnailMethod, true, function (dataUrl) { + _this10.emit("thumbnail", file, dataUrl); + _this10._processingThumbnail = false; + return _this10._processThumbnailQueue(); + }); + } + + // Can be called by the user to remove a file - Dropzone.prototype.removeFile = function(file) { + }, { + key: "removeFile", + value: function removeFile(file) { if (file.status === Dropzone.UPLOADING) { this.cancelUpload(file); } this.files = without(this.files, file); + this.emit("removedfile", file); if (this.files.length === 0) { return this.emit("reset"); } - }; + } + + // Removes all files that aren't currently processed from the list - Dropzone.prototype.removeAllFiles = function(cancelIfNecessary) { - var file, _i, _len, _ref; + }, { + key: "removeAllFiles", + value: function removeAllFiles(cancelIfNecessary) { + // Create a copy of files since removeFile() changes the @files array. if (cancelIfNecessary == null) { cancelIfNecessary = false; } - _ref = this.files.slice(); - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - file = _ref[_i]; + for (var _iterator18 = this.files.slice(), _isArray18 = true, _i19 = 0, _iterator18 = _isArray18 ? _iterator18 : _iterator18[Symbol.iterator]();;) { + var _ref17; + + if (_isArray18) { + if (_i19 >= _iterator18.length) break; + _ref17 = _iterator18[_i19++]; + } else { + _i19 = _iterator18.next(); + if (_i19.done) break; + _ref17 = _i19.value; + } + + var file = _ref17; + if (file.status !== Dropzone.UPLOADING || cancelIfNecessary) { this.removeFile(file); } } return null; - }; + } - Dropzone.prototype.createThumbnail = function(file, callback) { - var fileReader; - fileReader = new FileReader; - fileReader.onload = (function(_this) { - return function() { - if (file.type === "image/svg+xml") { - _this.emit("thumbnail", file, fileReader.result); - if (callback != null) { - callback(); - } - return; + // Resizes an image before it gets sent to the server. This function is the default behavior of + // `options.transformFile` if `resizeWidth` or `resizeHeight` are set. The callback is invoked with + // the resized blob. + + }, { + key: "resizeImage", + value: function resizeImage(file, width, height, resizeMethod, callback) { + var _this11 = this; + + return this.createThumbnail(file, width, height, resizeMethod, true, function (dataUrl, canvas) { + if (canvas == null) { + // The image has not been resized + return callback(file); + } else { + var resizeMimeType = _this11.options.resizeMimeType; + + if (resizeMimeType == null) { + resizeMimeType = file.type; } - return _this.createThumbnailFromUrl(file, fileReader.result, callback); - }; - })(this); + var resizedDataURL = canvas.toDataURL(resizeMimeType, _this11.options.resizeQuality); + if (resizeMimeType === 'image/jpeg' || resizeMimeType === 'image/jpg') { + // Now add the original EXIF information + resizedDataURL = ExifRestore.restore(file.dataURL, resizedDataURL); + } + return callback(Dropzone.dataURItoBlob(resizedDataURL)); + } + }); + } + }, { + key: "createThumbnail", + value: function createThumbnail(file, width, height, resizeMethod, fixOrientation, callback) { + var _this12 = this; + + var fileReader = new FileReader(); + + fileReader.onload = function () { + + file.dataURL = fileReader.result; + + // Don't bother creating a thumbnail for SVG images since they're vector + if (file.type === "image/svg+xml") { + if (callback != null) { + callback(fileReader.result); + } + return; + } + + return _this12.createThumbnailFromUrl(file, width, height, resizeMethod, fixOrientation, callback); + }; + return fileReader.readAsDataURL(file); - }; + } + }, { + key: "createThumbnailFromUrl", + value: function createThumbnailFromUrl(file, width, height, resizeMethod, fixOrientation, callback, crossOrigin) { + var _this13 = this; + + // Not using `new Image` here because of a bug in latest Chrome versions. + // See https://github.com/enyo/dropzone/pull/226 + var img = document.createElement("img"); + + if (crossOrigin) { + img.crossOrigin = crossOrigin; + } + + img.onload = function () { + var loadExif = function loadExif(callback) { + return callback(1); + }; + if (typeof EXIF !== 'undefined' && EXIF !== null && fixOrientation) { + loadExif = function loadExif(callback) { + return EXIF.getData(img, function () { + return callback(EXIF.getTag(this, 'Orientation')); + }); + }; + } - Dropzone.prototype.createThumbnailFromUrl = function(file, imageUrl, callback) { - var img; - img = document.createElement("img"); - img.onload = (function(_this) { - return function() { - var canvas, ctx, resizeInfo, thumbnail, _ref, _ref1, _ref2, _ref3; + return loadExif(function (orientation) { file.width = img.width; file.height = img.height; - resizeInfo = _this.options.resize.call(_this, file); - if (resizeInfo.trgWidth == null) { - resizeInfo.trgWidth = resizeInfo.optWidth; - } - if (resizeInfo.trgHeight == null) { - resizeInfo.trgHeight = resizeInfo.optHeight; - } - canvas = document.createElement("canvas"); - ctx = canvas.getContext("2d"); + + var resizeInfo = _this13.options.resize.call(_this13, file, width, height, resizeMethod); + + var canvas = document.createElement("canvas"); + var ctx = canvas.getContext("2d"); + canvas.width = resizeInfo.trgWidth; canvas.height = resizeInfo.trgHeight; - drawImageIOSFix(ctx, img, (_ref = resizeInfo.srcX) != null ? _ref : 0, (_ref1 = resizeInfo.srcY) != null ? _ref1 : 0, resizeInfo.srcWidth, resizeInfo.srcHeight, (_ref2 = resizeInfo.trgX) != null ? _ref2 : 0, (_ref3 = resizeInfo.trgY) != null ? _ref3 : 0, resizeInfo.trgWidth, resizeInfo.trgHeight); - thumbnail = canvas.toDataURL("image/png"); - _this.emit("thumbnail", file, thumbnail); + + if (orientation > 4) { + canvas.width = resizeInfo.trgHeight; + canvas.height = resizeInfo.trgWidth; + } + + switch (orientation) { + case 2: + // horizontal flip + ctx.translate(canvas.width, 0); + ctx.scale(-1, 1); + break; + case 3: + // 180° rotate left + ctx.translate(canvas.width, canvas.height); + ctx.rotate(Math.PI); + break; + case 4: + // vertical flip + ctx.translate(0, canvas.height); + ctx.scale(1, -1); + break; + case 5: + // vertical flip + 90 rotate right + ctx.rotate(0.5 * Math.PI); + ctx.scale(1, -1); + break; + case 6: + // 90° rotate right + ctx.rotate(0.5 * Math.PI); + ctx.translate(0, -canvas.width); + break; + case 7: + // horizontal flip + 90 rotate right + ctx.rotate(0.5 * Math.PI); + ctx.translate(canvas.height, -canvas.width); + ctx.scale(-1, 1); + break; + case 8: + // 90° rotate left + ctx.rotate(-0.5 * Math.PI); + ctx.translate(-canvas.height, 0); + break; + } + + // This is a bugfix for iOS' scaling bug. + drawImageIOSFix(ctx, img, resizeInfo.srcX != null ? resizeInfo.srcX : 0, resizeInfo.srcY != null ? resizeInfo.srcY : 0, resizeInfo.srcWidth, resizeInfo.srcHeight, resizeInfo.trgX != null ? resizeInfo.trgX : 0, resizeInfo.trgY != null ? resizeInfo.trgY : 0, resizeInfo.trgWidth, resizeInfo.trgHeight); + + var thumbnail = canvas.toDataURL("image/png"); + if (callback != null) { - return callback(); + return callback(thumbnail, canvas); } - }; - })(this); + }); + }; + if (callback != null) { img.onerror = callback; } - return img.src = imageUrl; - }; - Dropzone.prototype.processQueue = function() { - var i, parallelUploads, processingLength, queuedFiles; - parallelUploads = this.options.parallelUploads; - processingLength = this.getUploadingFiles().length; - i = processingLength; + return img.src = file.dataURL; + } + + // Goes through the queue and processes files if there aren't too many already. + + }, { + key: "processQueue", + value: function processQueue() { + var parallelUploads = this.options.parallelUploads; + + var processingLength = this.getUploadingFiles().length; + var i = processingLength; + + // There are already at least as many files uploading than should be if (processingLength >= parallelUploads) { return; } - queuedFiles = this.getQueuedFiles(); + + var queuedFiles = this.getQueuedFiles(); + if (!(queuedFiles.length > 0)) { return; } + if (this.options.uploadMultiple) { + // The files should be uploaded in one request return this.processFiles(queuedFiles.slice(0, parallelUploads - processingLength)); } else { while (i < parallelUploads) { if (!queuedFiles.length) { return; - } + } // Nothing left to process this.processFile(queuedFiles.shift()); i++; } } - }; + } + + // Wrapper for `processFiles` - Dropzone.prototype.processFile = function(file) { + }, { + key: "processFile", + value: function processFile(file) { return this.processFiles([file]); - }; + } + + // Loads the file, then calls finishedLoading() + + }, { + key: "processFiles", + value: function processFiles(files) { + for (var _iterator19 = files, _isArray19 = true, _i20 = 0, _iterator19 = _isArray19 ? _iterator19 : _iterator19[Symbol.iterator]();;) { + var _ref18; + + if (_isArray19) { + if (_i20 >= _iterator19.length) break; + _ref18 = _iterator19[_i20++]; + } else { + _i20 = _iterator19.next(); + if (_i20.done) break; + _ref18 = _i20.value; + } - Dropzone.prototype.processFiles = function(files) { - var file, _i, _len; - for (_i = 0, _len = files.length; _i < _len; _i++) { - file = files[_i]; - file.processing = true; + var file = _ref18; + + file.processing = true; // Backwards compatibility file.status = Dropzone.UPLOADING; + this.emit("processing", file); } + if (this.options.uploadMultiple) { this.emit("processingmultiple", files); } + return this.uploadFiles(files); - }; + } + }, { + key: "_getFilesWithXhr", + value: function _getFilesWithXhr(xhr) { + var files = void 0; + return files = this.files.filter(function (file) { + return file.xhr === xhr; + }).map(function (file) { + return file; + }); + } - Dropzone.prototype._getFilesWithXhr = function(xhr) { - var file, files; - return files = (function() { - var _i, _len, _ref, _results; - _ref = this.files; - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - file = _ref[_i]; - if (file.xhr === xhr) { - _results.push(file); - } - } - return _results; - }).call(this); - }; + // Cancels the file upload and sets the status to CANCELED + // **if** the file is actually being uploaded. + // If it's still in the queue, the file is being removed from it and the status + // set to CANCELED. - Dropzone.prototype.cancelUpload = function(file) { - var groupedFile, groupedFiles, _i, _j, _len, _len1, _ref; + }, { + key: "cancelUpload", + value: function cancelUpload(file) { if (file.status === Dropzone.UPLOADING) { - groupedFiles = this._getFilesWithXhr(file.xhr); - for (_i = 0, _len = groupedFiles.length; _i < _len; _i++) { - groupedFile = groupedFiles[_i]; + var groupedFiles = this._getFilesWithXhr(file.xhr); + for (var _iterator20 = groupedFiles, _isArray20 = true, _i21 = 0, _iterator20 = _isArray20 ? _iterator20 : _iterator20[Symbol.iterator]();;) { + var _ref19; + + if (_isArray20) { + if (_i21 >= _iterator20.length) break; + _ref19 = _iterator20[_i21++]; + } else { + _i21 = _iterator20.next(); + if (_i21.done) break; + _ref19 = _i21.value; + } + + var groupedFile = _ref19; + groupedFile.status = Dropzone.CANCELED; } - file.xhr.abort(); - for (_j = 0, _len1 = groupedFiles.length; _j < _len1; _j++) { - groupedFile = groupedFiles[_j]; - this.emit("canceled", groupedFile); + if (typeof file.xhr !== 'undefined') { + file.xhr.abort(); + } + for (var _iterator21 = groupedFiles, _isArray21 = true, _i22 = 0, _iterator21 = _isArray21 ? _iterator21 : _iterator21[Symbol.iterator]();;) { + var _ref20; + + if (_isArray21) { + if (_i22 >= _iterator21.length) break; + _ref20 = _iterator21[_i22++]; + } else { + _i22 = _iterator21.next(); + if (_i22.done) break; + _ref20 = _i22.value; + } + + var _groupedFile = _ref20; + + this.emit("canceled", _groupedFile); } if (this.options.uploadMultiple) { this.emit("canceledmultiple", groupedFiles); } - } else if ((_ref = file.status) === Dropzone.ADDED || _ref === Dropzone.QUEUED) { + } else if (file.status === Dropzone.ADDED || file.status === Dropzone.QUEUED) { file.status = Dropzone.CANCELED; this.emit("canceled", file); if (this.options.uploadMultiple) { this.emit("canceledmultiple", [file]); } } + if (this.options.autoProcessQueue) { return this.processQueue(); } - }; - - resolveOption = function() { - var args, option; - option = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + } + }, { + key: "resolveOption", + value: function resolveOption(option) { if (typeof option === 'function') { + for (var _len3 = arguments.length, args = Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) { + args[_key3 - 1] = arguments[_key3]; + } + return option.apply(this, args); } return option; - }; - - Dropzone.prototype.uploadFile = function(file) { + } + }, { + key: "uploadFile", + value: function uploadFile(file) { return this.uploadFiles([file]); - }; + } + }, { + key: "uploadFiles", + value: function uploadFiles(files) { + var _this14 = this; - Dropzone.prototype.uploadFiles = function(files) { - var file, formData, handleError, headerName, headerValue, headers, i, input, inputName, inputType, key, method, option, progressObj, response, updateProgress, url, value, xhr, _i, _j, _k, _l, _len, _len1, _len2, _len3, _m, _ref, _ref1, _ref2, _ref3, _ref4, _ref5; - xhr = new XMLHttpRequest(); - for (_i = 0, _len = files.length; _i < _len; _i++) { - file = files[_i]; - file.xhr = xhr; - } - method = resolveOption(this.options.method, files); - url = resolveOption(this.options.url, files); - xhr.open(method, url, true); - xhr.withCredentials = !!this.options.withCredentials; - response = null; - handleError = (function(_this) { - return function() { - var _j, _len1, _results; - _results = []; - for (_j = 0, _len1 = files.length; _j < _len1; _j++) { - file = files[_j]; - _results.push(_this._errorProcessing(files, response || _this.options.dictResponseError.replace("{{statusCode}}", xhr.status), xhr)); - } - return _results; - }; - })(this); - updateProgress = (function(_this) { - return function(e) { - var allFilesFinished, progress, _j, _k, _l, _len1, _len2, _len3, _results; - if (e != null) { - progress = 100 * e.loaded / e.total; - for (_j = 0, _len1 = files.length; _j < _len1; _j++) { - file = files[_j]; - file.upload = { - progress: progress, - total: e.total, - bytesSent: e.loaded - }; + this._transformFiles(files, function (transformedFiles) { + if (files[0].upload.chunked) { + // This file should be sent in chunks! + + // If the chunking option is set, we **know** that there can only be **one** file, since + // uploadMultiple is not allowed with this option. + var file = files[0]; + var transformedFile = transformedFiles[0]; + var startedChunkCount = 0; + + file.upload.chunks = []; + + var handleNextChunk = function handleNextChunk() { + var chunkIndex = 0; + + // Find the next item in file.upload.chunks that is not defined yet. + while (file.upload.chunks[chunkIndex] !== undefined) { + chunkIndex++; } - } else { - allFilesFinished = true; - progress = 100; - for (_k = 0, _len2 = files.length; _k < _len2; _k++) { - file = files[_k]; - if (!(file.upload.progress === 100 && file.upload.bytesSent === file.upload.total)) { - allFilesFinished = false; + + // This means, that all chunks have already been started. + if (chunkIndex >= file.upload.totalChunkCount) return; + + startedChunkCount++; + + var start = chunkIndex * _this14.options.chunkSize; + var end = Math.min(start + _this14.options.chunkSize, file.size); + + var dataBlock = { + name: _this14._getParamName(0), + data: transformedFile.webkitSlice ? transformedFile.webkitSlice(start, end) : transformedFile.slice(start, end), + filename: file.upload.filename, + chunkIndex: chunkIndex + }; + + file.upload.chunks[chunkIndex] = { + file: file, + index: chunkIndex, + dataBlock: dataBlock, // In case we want to retry. + status: Dropzone.UPLOADING, + progress: 0, + retries: 0 // The number of times this block has been retried. + }; + + _this14._uploadData(files, [dataBlock]); + }; + + file.upload.finishedChunkUpload = function (chunk) { + var allFinished = true; + chunk.status = Dropzone.SUCCESS; + + // Clear the data from the chunk + chunk.dataBlock = null; + // Leaving this reference to xhr intact here will cause memory leaks in some browsers + chunk.xhr = null; + + for (var i = 0; i < file.upload.totalChunkCount; i++) { + if (file.upload.chunks[i] === undefined) { + return handleNextChunk(); + } + if (file.upload.chunks[i].status !== Dropzone.SUCCESS) { + allFinished = false; } - file.upload.progress = progress; - file.upload.bytesSent = file.upload.total; } - if (allFilesFinished) { - return; + + if (allFinished) { + _this14.options.chunksUploaded(file, function () { + _this14._finished(files, '', null); + }); } - } - _results = []; - for (_l = 0, _len3 = files.length; _l < _len3; _l++) { - file = files[_l]; - _results.push(_this.emit("uploadprogress", file, progress, file.upload.bytesSent)); - } - return _results; - }; - })(this); - xhr.onload = (function(_this) { - return function(e) { - var _ref; - if (files[0].status === Dropzone.CANCELED) { - return; - } - if (xhr.readyState !== 4) { - return; - } - response = xhr.responseText; - if (xhr.getResponseHeader("content-type") && ~xhr.getResponseHeader("content-type").indexOf("application/json")) { - try { - response = JSON.parse(response); - } catch (_error) { - e = _error; - response = "Invalid JSON response from server."; + }; + + if (_this14.options.parallelChunkUploads) { + for (var i = 0; i < file.upload.totalChunkCount; i++) { + handleNextChunk(); } - } - updateProgress(); - if (!((200 <= (_ref = xhr.status) && _ref < 300))) { - return handleError(); } else { - return _this._finished(files, response, e); + handleNextChunk(); } - }; - })(this); - xhr.onerror = (function(_this) { - return function() { - if (files[0].status === Dropzone.CANCELED) { - return; + } else { + var dataBlocks = []; + for (var _i23 = 0; _i23 < files.length; _i23++) { + dataBlocks[_i23] = { + name: _this14._getParamName(_i23), + data: transformedFiles[_i23], + filename: files[_i23].upload.filename + }; } - return handleError(); - }; - })(this); - progressObj = (_ref = xhr.upload) != null ? _ref : xhr; - progressObj.onprogress = updateProgress; - headers = { + _this14._uploadData(files, dataBlocks); + } + }); + } + + /// Returns the right chunk for given file and xhr + + }, { + key: "_getChunk", + value: function _getChunk(file, xhr) { + for (var i = 0; i < file.upload.totalChunkCount; i++) { + if (file.upload.chunks[i] !== undefined && file.upload.chunks[i].xhr === xhr) { + return file.upload.chunks[i]; + } + } + } + + // This function actually uploads the file(s) to the server. + // If dataBlocks contains the actual data to upload (meaning, that this could either be transformed + // files, or individual chunks for chunked upload). + + }, { + key: "_uploadData", + value: function _uploadData(files, dataBlocks) { + var _this15 = this; + + var xhr = new XMLHttpRequest(); + + // Put the xhr object in the file objects to be able to reference it later. + for (var _iterator22 = files, _isArray22 = true, _i24 = 0, _iterator22 = _isArray22 ? _iterator22 : _iterator22[Symbol.iterator]();;) { + var _ref21; + + if (_isArray22) { + if (_i24 >= _iterator22.length) break; + _ref21 = _iterator22[_i24++]; + } else { + _i24 = _iterator22.next(); + if (_i24.done) break; + _ref21 = _i24.value; + } + + var file = _ref21; + + file.xhr = xhr; + } + if (files[0].upload.chunked) { + // Put the xhr object in the right chunk object, so it can be associated later, and found with _getChunk + files[0].upload.chunks[dataBlocks[0].chunkIndex].xhr = xhr; + } + + var method = this.resolveOption(this.options.method, files); + var url = this.resolveOption(this.options.url, files); + xhr.open(method, url, true); + + // Setting the timeout after open because of IE11 issue: https://gitlab.com/meno/dropzone/issues/8 + xhr.timeout = this.resolveOption(this.options.timeout, files); + + // Has to be after `.open()`. See https://github.com/enyo/dropzone/issues/179 + xhr.withCredentials = !!this.options.withCredentials; + + xhr.onload = function (e) { + _this15._finishedUploading(files, xhr, e); + }; + + xhr.onerror = function () { + _this15._handleUploadError(files, xhr); + }; + + // Some browsers do not have the .upload property + var progressObj = xhr.upload != null ? xhr.upload : xhr; + progressObj.onprogress = function (e) { + return _this15._updateFilesUploadProgress(files, xhr, e); + }; + + var headers = { "Accept": "application/json", "Cache-Control": "no-cache", "X-Requested-With": "XMLHttpRequest" }; + if (this.options.headers) { - extend(headers, this.options.headers); + Dropzone.extend(headers, this.options.headers); } - for (headerName in headers) { - headerValue = headers[headerName]; - xhr.setRequestHeader(headerName, headerValue); + + for (var headerName in headers) { + var headerValue = headers[headerName]; + if (headerValue) { + xhr.setRequestHeader(headerName, headerValue); + } } - formData = new FormData(); + + var formData = new FormData(); + + // Adding all @options parameters if (this.options.params) { - _ref1 = this.options.params; - for (key in _ref1) { - value = _ref1[key]; + var additionalParams = this.options.params; + if (typeof additionalParams === 'function') { + additionalParams = additionalParams.call(this, files, xhr, files[0].upload.chunked ? this._getChunk(files[0], xhr) : null); + } + + for (var key in additionalParams) { + var value = additionalParams[key]; formData.append(key, value); } } - for (_j = 0, _len1 = files.length; _j < _len1; _j++) { - file = files[_j]; - this.emit("sending", file, xhr, formData); + + // Let the user add additional data if necessary + for (var _iterator23 = files, _isArray23 = true, _i25 = 0, _iterator23 = _isArray23 ? _iterator23 : _iterator23[Symbol.iterator]();;) { + var _ref22; + + if (_isArray23) { + if (_i25 >= _iterator23.length) break; + _ref22 = _iterator23[_i25++]; + } else { + _i25 = _iterator23.next(); + if (_i25.done) break; + _ref22 = _i25.value; + } + + var _file = _ref22; + + this.emit("sending", _file, xhr, formData); } if (this.options.uploadMultiple) { this.emit("sendingmultiple", files, xhr, formData); } + + this._addFormElementData(formData); + + // Finally add the files + // Has to be last because some servers (eg: S3) expect the file to be the last parameter + for (var i = 0; i < dataBlocks.length; i++) { + var dataBlock = dataBlocks[i]; + formData.append(dataBlock.name, dataBlock.data, dataBlock.filename); + } + + this.submitRequest(xhr, formData, files); + } + + // Transforms all files with this.options.transformFile and invokes done with the transformed files when done. + + }, { + key: "_transformFiles", + value: function _transformFiles(files, done) { + var _this16 = this; + + var transformedFiles = []; + // Clumsy way of handling asynchronous calls, until I get to add a proper Future library. + var doneCounter = 0; + + var _loop = function _loop(i) { + _this16.options.transformFile.call(_this16, files[i], function (transformedFile) { + transformedFiles[i] = transformedFile; + if (++doneCounter === files.length) { + done(transformedFiles); + } + }); + }; + + for (var i = 0; i < files.length; i++) { + _loop(i); + } + } + + // Takes care of adding other input elements of the form to the AJAX request + + }, { + key: "_addFormElementData", + value: function _addFormElementData(formData) { + // Take care of other input elements if (this.element.tagName === "FORM") { - _ref2 = this.element.querySelectorAll("input, textarea, select, button"); - for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) { - input = _ref2[_k]; - inputName = input.getAttribute("name"); - inputType = input.getAttribute("type"); + for (var _iterator24 = this.element.querySelectorAll("input, textarea, select, button"), _isArray24 = true, _i26 = 0, _iterator24 = _isArray24 ? _iterator24 : _iterator24[Symbol.iterator]();;) { + var _ref23; + + if (_isArray24) { + if (_i26 >= _iterator24.length) break; + _ref23 = _iterator24[_i26++]; + } else { + _i26 = _iterator24.next(); + if (_i26.done) break; + _ref23 = _i26.value; + } + + var input = _ref23; + + var inputName = input.getAttribute("name"); + var inputType = input.getAttribute("type"); + if (inputType) inputType = inputType.toLowerCase(); + + // If the input doesn't have a name, we can't use it. + if (typeof inputName === 'undefined' || inputName === null) continue; + if (input.tagName === "SELECT" && input.hasAttribute("multiple")) { - _ref3 = input.options; - for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) { - option = _ref3[_l]; + // Possibly multiple values + for (var _iterator25 = input.options, _isArray25 = true, _i27 = 0, _iterator25 = _isArray25 ? _iterator25 : _iterator25[Symbol.iterator]();;) { + var _ref24; + + if (_isArray25) { + if (_i27 >= _iterator25.length) break; + _ref24 = _iterator25[_i27++]; + } else { + _i27 = _iterator25.next(); + if (_i27.done) break; + _ref24 = _i27.value; + } + + var option = _ref24; + if (option.selected) { formData.append(inputName, option.value); } } - } else if (!inputType || ((_ref4 = inputType.toLowerCase()) !== "checkbox" && _ref4 !== "radio") || input.checked) { + } else if (!inputType || inputType !== "checkbox" && inputType !== "radio" || input.checked) { formData.append(inputName, input.value); } } } - for (i = _m = 0, _ref5 = files.length - 1; 0 <= _ref5 ? _m <= _ref5 : _m >= _ref5; i = 0 <= _ref5 ? ++_m : --_m) { - formData.append(this._getParamName(i), files[i], files[i].name); + } + + // Invoked when there is new progress information about given files. + // If e is not provided, it is assumed that the upload is finished. + + }, { + key: "_updateFilesUploadProgress", + value: function _updateFilesUploadProgress(files, xhr, e) { + var progress = void 0; + if (typeof e !== 'undefined') { + progress = 100 * e.loaded / e.total; + + if (files[0].upload.chunked) { + var file = files[0]; + // Since this is a chunked upload, we need to update the appropriate chunk progress. + var chunk = this._getChunk(file, xhr); + chunk.progress = progress; + chunk.total = e.total; + chunk.bytesSent = e.loaded; + var fileProgress = 0, + fileTotal = void 0, + fileBytesSent = void 0; + file.upload.progress = 0; + file.upload.total = 0; + file.upload.bytesSent = 0; + for (var i = 0; i < file.upload.totalChunkCount; i++) { + if (file.upload.chunks[i] !== undefined && file.upload.chunks[i].progress !== undefined) { + file.upload.progress += file.upload.chunks[i].progress; + file.upload.total += file.upload.chunks[i].total; + file.upload.bytesSent += file.upload.chunks[i].bytesSent; + } + } + file.upload.progress = file.upload.progress / file.upload.totalChunkCount; + } else { + for (var _iterator26 = files, _isArray26 = true, _i28 = 0, _iterator26 = _isArray26 ? _iterator26 : _iterator26[Symbol.iterator]();;) { + var _ref25; + + if (_isArray26) { + if (_i28 >= _iterator26.length) break; + _ref25 = _iterator26[_i28++]; + } else { + _i28 = _iterator26.next(); + if (_i28.done) break; + _ref25 = _i28.value; + } + + var _file2 = _ref25; + + _file2.upload.progress = progress; + _file2.upload.total = e.total; + _file2.upload.bytesSent = e.loaded; + } + } + for (var _iterator27 = files, _isArray27 = true, _i29 = 0, _iterator27 = _isArray27 ? _iterator27 : _iterator27[Symbol.iterator]();;) { + var _ref26; + + if (_isArray27) { + if (_i29 >= _iterator27.length) break; + _ref26 = _iterator27[_i29++]; + } else { + _i29 = _iterator27.next(); + if (_i29.done) break; + _ref26 = _i29.value; + } + + var _file3 = _ref26; + + this.emit("uploadprogress", _file3, _file3.upload.progress, _file3.upload.bytesSent); + } + } else { + // Called when the file finished uploading + + var allFilesFinished = true; + + progress = 100; + + for (var _iterator28 = files, _isArray28 = true, _i30 = 0, _iterator28 = _isArray28 ? _iterator28 : _iterator28[Symbol.iterator]();;) { + var _ref27; + + if (_isArray28) { + if (_i30 >= _iterator28.length) break; + _ref27 = _iterator28[_i30++]; + } else { + _i30 = _iterator28.next(); + if (_i30.done) break; + _ref27 = _i30.value; + } + + var _file4 = _ref27; + + if (_file4.upload.progress !== 100 || _file4.upload.bytesSent !== _file4.upload.total) { + allFilesFinished = false; + } + _file4.upload.progress = progress; + _file4.upload.bytesSent = _file4.upload.total; + } + + // Nothing to do, all files already at 100% + if (allFilesFinished) { + return; + } + + for (var _iterator29 = files, _isArray29 = true, _i31 = 0, _iterator29 = _isArray29 ? _iterator29 : _iterator29[Symbol.iterator]();;) { + var _ref28; + + if (_isArray29) { + if (_i31 >= _iterator29.length) break; + _ref28 = _iterator29[_i31++]; + } else { + _i31 = _iterator29.next(); + if (_i31.done) break; + _ref28 = _i31.value; + } + + var _file5 = _ref28; + + this.emit("uploadprogress", _file5, progress, _file5.upload.bytesSent); + } } - return xhr.send(formData); - }; + } + }, { + key: "_finishedUploading", + value: function _finishedUploading(files, xhr, e) { + var response = void 0; + + if (files[0].status === Dropzone.CANCELED) { + return; + } + + if (xhr.readyState !== 4) { + return; + } + + if (xhr.responseType !== 'arraybuffer' && xhr.responseType !== 'blob') { + response = xhr.responseText; + + if (xhr.getResponseHeader("content-type") && ~xhr.getResponseHeader("content-type").indexOf("application/json")) { + try { + response = JSON.parse(response); + } catch (error) { + e = error; + response = "Invalid JSON response from server."; + } + } + } + + this._updateFilesUploadProgress(files); + + if (!(200 <= xhr.status && xhr.status < 300)) { + this._handleUploadError(files, xhr, response); + } else { + if (files[0].upload.chunked) { + files[0].upload.finishedChunkUpload(this._getChunk(files[0], xhr)); + } else { + this._finished(files, response, e); + } + } + } + }, { + key: "_handleUploadError", + value: function _handleUploadError(files, xhr, response) { + if (files[0].status === Dropzone.CANCELED) { + return; + } + + if (files[0].upload.chunked && this.options.retryChunks) { + var chunk = this._getChunk(files[0], xhr); + if (chunk.retries++ < this.options.retryChunksLimit) { + this._uploadData(files, [chunk.dataBlock]); + return; + } else { + console.warn('Retried this chunk too often. Giving up.'); + } + } + + for (var _iterator30 = files, _isArray30 = true, _i32 = 0, _iterator30 = _isArray30 ? _iterator30 : _iterator30[Symbol.iterator]();;) { + var _ref29; + + if (_isArray30) { + if (_i32 >= _iterator30.length) break; + _ref29 = _iterator30[_i32++]; + } else { + _i32 = _iterator30.next(); + if (_i32.done) break; + _ref29 = _i32.value; + } + + var file = _ref29; + + this._errorProcessing(files, response || this.options.dictResponseError.replace("{{statusCode}}", xhr.status), xhr); + } + } + }, { + key: "submitRequest", + value: function submitRequest(xhr, formData, files) { + xhr.send(formData); + } + + // Called internally when processing is finished. + // Individual callbacks have to be called in the appropriate sections. + + }, { + key: "_finished", + value: function _finished(files, responseText, e) { + for (var _iterator31 = files, _isArray31 = true, _i33 = 0, _iterator31 = _isArray31 ? _iterator31 : _iterator31[Symbol.iterator]();;) { + var _ref30; + + if (_isArray31) { + if (_i33 >= _iterator31.length) break; + _ref30 = _iterator31[_i33++]; + } else { + _i33 = _iterator31.next(); + if (_i33.done) break; + _ref30 = _i33.value; + } + + var file = _ref30; - Dropzone.prototype._finished = function(files, responseText, e) { - var file, _i, _len; - for (_i = 0, _len = files.length; _i < _len; _i++) { - file = files[_i]; file.status = Dropzone.SUCCESS; this.emit("success", file, responseText, e); this.emit("complete", file); @@ -1359,15 +2814,32 @@ this.emit("successmultiple", files, responseText, e); this.emit("completemultiple", files); } + if (this.options.autoProcessQueue) { return this.processQueue(); } - }; + } + + // Called internally when processing is finished. + // Individual callbacks have to be called in the appropriate sections. + + }, { + key: "_errorProcessing", + value: function _errorProcessing(files, message, xhr) { + for (var _iterator32 = files, _isArray32 = true, _i34 = 0, _iterator32 = _isArray32 ? _iterator32 : _iterator32[Symbol.iterator]();;) { + var _ref31; + + if (_isArray32) { + if (_i34 >= _iterator32.length) break; + _ref31 = _iterator32[_i34++]; + } else { + _i34 = _iterator32.next(); + if (_i34.done) break; + _ref31 = _i34.value; + } + + var file = _ref31; - Dropzone.prototype._errorProcessing = function(files, message, xhr) { - var file, _i, _len; - for (_i = 0, _len = files.length; _i < _len; _i++) { - file = files[_i]; file.status = Dropzone.ERROR; this.emit("error", file, message, xhr); this.emit("complete", file); @@ -1376,353 +2848,688 @@ this.emit("errormultiple", files, message, xhr); this.emit("completemultiple", files); } + if (this.options.autoProcessQueue) { return this.processQueue(); } - }; - - return Dropzone; - - })(Emitter); - - Dropzone.version = "4.0.1"; + } + }], [{ + key: "uuidv4", + value: function uuidv4() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { + var r = Math.random() * 16 | 0, + v = c === 'x' ? r : r & 0x3 | 0x8; + return v.toString(16); + }); + } + }]); + + return Dropzone; +}(Emitter); + +Dropzone.initClass(); + +Dropzone.version = "5.5.1"; + +// This is a map of options for your different dropzones. Add configurations +// to this object for your different dropzone elemens. +// +// Example: +// +// Dropzone.options.myDropzoneElementId = { maxFilesize: 1 }; +// +// To disable autoDiscover for a specific element, you can set `false` as an option: +// +// Dropzone.options.myDisabledElementId = false; +// +// And in html: +// +//
+Dropzone.options = {}; + +// Returns the options for an element or undefined if none available. +Dropzone.optionsForElement = function (element) { + // Get the `Dropzone.options.elementId` for this element if it exists + if (element.getAttribute("id")) { + return Dropzone.options[camelize(element.getAttribute("id"))]; + } else { + return undefined; + } +}; - Dropzone.options = {}; +// Holds a list of all dropzone instances +Dropzone.instances = []; - Dropzone.optionsForElement = function(element) { - if (element.getAttribute("id")) { - return Dropzone.options[camelize(element.getAttribute("id"))]; - } else { - return void 0; - } - }; +// Returns the dropzone for given element if any +Dropzone.forElement = function (element) { + if (typeof element === "string") { + element = document.querySelector(element); + } + if ((element != null ? element.dropzone : undefined) == null) { + throw new Error("No Dropzone found for given element. This is probably because you're trying to access it before Dropzone had the time to initialize. Use the `init` option to setup any additional observers on your Dropzone."); + } + return element.dropzone; +}; - Dropzone.instances = []; +// Set to false if you don't want Dropzone to automatically find and attach to .dropzone elements. +Dropzone.autoDiscover = true; - Dropzone.forElement = function(element) { - if (typeof element === "string") { - element = document.querySelector(element); - } - if ((element != null ? element.dropzone : void 0) == null) { - throw new Error("No Dropzone found for given element. This is probably because you're trying to access it before Dropzone had the time to initialize. Use the `init` option to setup any additional observers on your Dropzone."); - } - return element.dropzone; - }; +// Looks for all .dropzone elements and creates a dropzone for them +Dropzone.discover = function () { + var dropzones = void 0; + if (document.querySelectorAll) { + dropzones = document.querySelectorAll(".dropzone"); + } else { + dropzones = []; + // IE :( + var checkElements = function checkElements(elements) { + return function () { + var result = []; + for (var _iterator33 = elements, _isArray33 = true, _i35 = 0, _iterator33 = _isArray33 ? _iterator33 : _iterator33[Symbol.iterator]();;) { + var _ref32; + + if (_isArray33) { + if (_i35 >= _iterator33.length) break; + _ref32 = _iterator33[_i35++]; + } else { + _i35 = _iterator33.next(); + if (_i35.done) break; + _ref32 = _i35.value; + } - Dropzone.autoDiscover = true; + var el = _ref32; - Dropzone.discover = function() { - var checkElements, dropzone, dropzones, _i, _len, _results; - if (document.querySelectorAll) { - dropzones = document.querySelectorAll(".dropzone"); - } else { - dropzones = []; - checkElements = function(elements) { - var el, _i, _len, _results; - _results = []; - for (_i = 0, _len = elements.length; _i < _len; _i++) { - el = elements[_i]; if (/(^| )dropzone($| )/.test(el.className)) { - _results.push(dropzones.push(el)); + result.push(dropzones.push(el)); } else { - _results.push(void 0); + result.push(undefined); } } - return _results; - }; - checkElements(document.getElementsByTagName("div")); - checkElements(document.getElementsByTagName("form")); - } - _results = []; - for (_i = 0, _len = dropzones.length; _i < _len; _i++) { - dropzone = dropzones[_i]; - if (Dropzone.optionsForElement(dropzone) !== false) { - _results.push(new Dropzone(dropzone)); + return result; + }(); + }; + checkElements(document.getElementsByTagName("div")); + checkElements(document.getElementsByTagName("form")); + } + + return function () { + var result = []; + for (var _iterator34 = dropzones, _isArray34 = true, _i36 = 0, _iterator34 = _isArray34 ? _iterator34 : _iterator34[Symbol.iterator]();;) { + var _ref33; + + if (_isArray34) { + if (_i36 >= _iterator34.length) break; + _ref33 = _iterator34[_i36++]; } else { - _results.push(void 0); + _i36 = _iterator34.next(); + if (_i36.done) break; + _ref33 = _i36.value; } - } - return _results; - }; - Dropzone.blacklistedBrowsers = [/opera.*Macintosh.*version\/12/i]; + var dropzone = _ref33; - Dropzone.isBrowserSupported = function() { - var capableBrowser, regex, _i, _len, _ref; - capableBrowser = true; - if (window.File && window.FileReader && window.FileList && window.Blob && window.FormData && document.querySelector) { - if (!("classList" in document.createElement("a"))) { - capableBrowser = false; + // Create a dropzone unless auto discover has been disabled for specific element + if (Dropzone.optionsForElement(dropzone) !== false) { + result.push(new Dropzone(dropzone)); } else { - _ref = Dropzone.blacklistedBrowsers; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - regex = _ref[_i]; - if (regex.test(navigator.userAgent)) { - capableBrowser = false; - continue; - } - } + result.push(undefined); } - } else { - capableBrowser = false; } - return capableBrowser; - }; + return result; + }(); +}; + +// Since the whole Drag'n'Drop API is pretty new, some browsers implement it, +// but not correctly. +// So I created a blacklist of userAgents. Yes, yes. Browser sniffing, I know. +// But what to do when browsers *theoretically* support an API, but crash +// when using it. +// +// This is a list of regular expressions tested against navigator.userAgent +// +// ** It should only be used on browser that *do* support the API, but +// incorrectly ** +// +Dropzone.blacklistedBrowsers = [ +// The mac os and windows phone version of opera 12 seems to have a problem with the File drag'n'drop API. +/opera.*(Macintosh|Windows Phone).*version\/12/i]; + +// Checks if the browser is supported +Dropzone.isBrowserSupported = function () { + var capableBrowser = true; + + if (window.File && window.FileReader && window.FileList && window.Blob && window.FormData && document.querySelector) { + if (!("classList" in document.createElement("a"))) { + capableBrowser = false; + } else { + // The browser supports the API, but may be blacklisted. + for (var _iterator35 = Dropzone.blacklistedBrowsers, _isArray35 = true, _i37 = 0, _iterator35 = _isArray35 ? _iterator35 : _iterator35[Symbol.iterator]();;) { + var _ref34; + + if (_isArray35) { + if (_i37 >= _iterator35.length) break; + _ref34 = _iterator35[_i37++]; + } else { + _i37 = _iterator35.next(); + if (_i37.done) break; + _ref34 = _i37.value; + } + + var regex = _ref34; - without = function(list, rejectedItem) { - var item, _i, _len, _results; - _results = []; - for (_i = 0, _len = list.length; _i < _len; _i++) { - item = list[_i]; - if (item !== rejectedItem) { - _results.push(item); + if (regex.test(navigator.userAgent)) { + capableBrowser = false; + continue; + } } } - return _results; - }; + } else { + capableBrowser = false; + } - camelize = function(str) { - return str.replace(/[\-_](\w)/g, function(match) { - return match.charAt(1).toUpperCase(); - }); - }; + return capableBrowser; +}; - Dropzone.createElement = function(string) { - var div; - div = document.createElement("div"); - div.innerHTML = string; - return div.childNodes[0]; - }; +Dropzone.dataURItoBlob = function (dataURI) { + // convert base64 to raw binary data held in a string + // doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this + var byteString = atob(dataURI.split(',')[1]); + + // separate out the mime component + var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; + + // write the bytes of the string to an ArrayBuffer + var ab = new ArrayBuffer(byteString.length); + var ia = new Uint8Array(ab); + for (var i = 0, end = byteString.length, asc = 0 <= end; asc ? i <= end : i >= end; asc ? i++ : i--) { + ia[i] = byteString.charCodeAt(i); + } - Dropzone.elementInside = function(element, container) { + // write the ArrayBuffer to a blob + return new Blob([ab], { type: mimeString }); +}; + +// Returns an array without the rejected item +var without = function without(list, rejectedItem) { + return list.filter(function (item) { + return item !== rejectedItem; + }).map(function (item) { + return item; + }); +}; + +// abc-def_ghi -> abcDefGhi +var camelize = function camelize(str) { + return str.replace(/[\-_](\w)/g, function (match) { + return match.charAt(1).toUpperCase(); + }); +}; + +// Creates an element from string +Dropzone.createElement = function (string) { + var div = document.createElement("div"); + div.innerHTML = string; + return div.childNodes[0]; +}; + +// Tests if given element is inside (or simply is) the container +Dropzone.elementInside = function (element, container) { + if (element === container) { + return true; + } // Coffeescript doesn't support do/while loops + while (element = element.parentNode) { if (element === container) { return true; } - while (element = element.parentNode) { - if (element === container) { - return true; + } + return false; +}; + +Dropzone.getElement = function (el, name) { + var element = void 0; + if (typeof el === "string") { + element = document.querySelector(el); + } else if (el.nodeType != null) { + element = el; + } + if (element == null) { + throw new Error("Invalid `" + name + "` option provided. Please provide a CSS selector or a plain HTML element."); + } + return element; +}; + +Dropzone.getElements = function (els, name) { + var el = void 0, + elements = void 0; + if (els instanceof Array) { + elements = []; + try { + for (var _iterator36 = els, _isArray36 = true, _i38 = 0, _iterator36 = _isArray36 ? _iterator36 : _iterator36[Symbol.iterator]();;) { + if (_isArray36) { + if (_i38 >= _iterator36.length) break; + el = _iterator36[_i38++]; + } else { + _i38 = _iterator36.next(); + if (_i38.done) break; + el = _i38.value; + } + + elements.push(this.getElement(el, name)); } + } catch (e) { + elements = null; } - return false; - }; + } else if (typeof els === "string") { + elements = []; + for (var _iterator37 = document.querySelectorAll(els), _isArray37 = true, _i39 = 0, _iterator37 = _isArray37 ? _iterator37 : _iterator37[Symbol.iterator]();;) { + if (_isArray37) { + if (_i39 >= _iterator37.length) break; + el = _iterator37[_i39++]; + } else { + _i39 = _iterator37.next(); + if (_i39.done) break; + el = _i39.value; + } - Dropzone.getElement = function(el, name) { - var element; - if (typeof el === "string") { - element = document.querySelector(el); - } else if (el.nodeType != null) { - element = el; + elements.push(el); } - if (element == null) { - throw new Error("Invalid `" + name + "` option provided. Please provide a CSS selector or a plain HTML element."); + } else if (els.nodeType != null) { + elements = [els]; + } + + if (elements == null || !elements.length) { + throw new Error("Invalid `" + name + "` option provided. Please provide a CSS selector, a plain HTML element or a list of those."); + } + + return elements; +}; + +// Asks the user the question and calls accepted or rejected accordingly +// +// The default implementation just uses `window.confirm` and then calls the +// appropriate callback. +Dropzone.confirm = function (question, accepted, rejected) { + if (window.confirm(question)) { + return accepted(); + } else if (rejected != null) { + return rejected(); + } +}; + +// Validates the mime type like this: +// +// https://developer.mozilla.org/en-US/docs/HTML/Element/input#attr-accept +Dropzone.isValidFile = function (file, acceptedFiles) { + if (!acceptedFiles) { + return true; + } // If there are no accepted mime types, it's OK + acceptedFiles = acceptedFiles.split(","); + + var mimeType = file.type; + var baseMimeType = mimeType.replace(/\/.*$/, ""); + + for (var _iterator38 = acceptedFiles, _isArray38 = true, _i40 = 0, _iterator38 = _isArray38 ? _iterator38 : _iterator38[Symbol.iterator]();;) { + var _ref35; + + if (_isArray38) { + if (_i40 >= _iterator38.length) break; + _ref35 = _iterator38[_i40++]; + } else { + _i40 = _iterator38.next(); + if (_i40.done) break; + _ref35 = _i40.value; } - return element; - }; - Dropzone.getElements = function(els, name) { - var e, el, elements, _i, _j, _len, _len1, _ref; - if (els instanceof Array) { - elements = []; - try { - for (_i = 0, _len = els.length; _i < _len; _i++) { - el = els[_i]; - elements.push(this.getElement(el, name)); - } - } catch (_error) { - e = _error; - elements = null; + var validType = _ref35; + + validType = validType.trim(); + if (validType.charAt(0) === ".") { + if (file.name.toLowerCase().indexOf(validType.toLowerCase(), file.name.length - validType.length) !== -1) { + return true; } - } else if (typeof els === "string") { - elements = []; - _ref = document.querySelectorAll(els); - for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) { - el = _ref[_j]; - elements.push(el); + } else if (/\/\*$/.test(validType)) { + // This is something like a image/* mime type + if (baseMimeType === validType.replace(/\/.*$/, "")) { + return true; + } + } else { + if (mimeType === validType) { + return true; } - } else if (els.nodeType != null) { - elements = [els]; - } - if (!((elements != null) && elements.length)) { - throw new Error("Invalid `" + name + "` option provided. Please provide a CSS selector, a plain HTML element or a list of those."); } - return elements; - }; + } - Dropzone.confirm = function(question, accepted, rejected) { - if (window.confirm(question)) { - return accepted(); - } else if (rejected != null) { - return rejected(); - } - }; + return false; +}; - Dropzone.isValidFile = function(file, acceptedFiles) { - var baseMimeType, mimeType, validType, _i, _len; - if (!acceptedFiles) { - return true; - } - acceptedFiles = acceptedFiles.split(","); - mimeType = file.type; - baseMimeType = mimeType.replace(/\/.*$/, ""); - for (_i = 0, _len = acceptedFiles.length; _i < _len; _i++) { - validType = acceptedFiles[_i]; - validType = validType.trim(); - if (validType.charAt(0) === ".") { - if (file.name.toLowerCase().indexOf(validType.toLowerCase(), file.name.length - validType.length) !== -1) { - return true; - } - } else if (/\/\*$/.test(validType)) { - if (baseMimeType === validType.replace(/\/.*$/, "")) { - return true; - } - } else { - if (mimeType === validType) { - return true; - } - } - } - return false; +// Augment jQuery +if (typeof jQuery !== 'undefined' && jQuery !== null) { + jQuery.fn.dropzone = function (options) { + return this.each(function () { + return new Dropzone(this, options); + }); }; +} - if (typeof jQuery !== "undefined" && jQuery !== null) { - jQuery.fn.dropzone = function(options) { - return this.each(function() { - return new Dropzone(this, options); - }); - }; - } +if (typeof module !== 'undefined' && module !== null) { + module.exports = Dropzone; +} else { + window.Dropzone = Dropzone; +} - if (typeof module !== "undefined" && module !== null) { - module.exports = Dropzone; - } else { - window.Dropzone = Dropzone; - } +// Dropzone file status codes +Dropzone.ADDED = "added"; - Dropzone.ADDED = "added"; +Dropzone.QUEUED = "queued"; +// For backwards compatibility. Now, if a file is accepted, it's either queued +// or uploading. +Dropzone.ACCEPTED = Dropzone.QUEUED; - Dropzone.QUEUED = "queued"; +Dropzone.UPLOADING = "uploading"; +Dropzone.PROCESSING = Dropzone.UPLOADING; // alias - Dropzone.ACCEPTED = Dropzone.QUEUED; +Dropzone.CANCELED = "canceled"; +Dropzone.ERROR = "error"; +Dropzone.SUCCESS = "success"; - Dropzone.UPLOADING = "uploading"; +/* - Dropzone.PROCESSING = Dropzone.UPLOADING; + Bugfix for iOS 6 and 7 + Source: http://stackoverflow.com/questions/11929099/html5-canvas-drawimage-ratio-bug-ios + based on the work of https://github.com/stomita/ios-imagefile-megapixel - Dropzone.CANCELED = "canceled"; + */ - Dropzone.ERROR = "error"; +// Detecting vertical squash in loaded image. +// Fixes a bug which squash image vertically while drawing into canvas for some images. +// This is a bug in iOS6 devices. This function from https://github.com/stomita/ios-imagefile-megapixel +var detectVerticalSquash = function detectVerticalSquash(img) { + var iw = img.naturalWidth; + var ih = img.naturalHeight; + var canvas = document.createElement("canvas"); + canvas.width = 1; + canvas.height = ih; + var ctx = canvas.getContext("2d"); + ctx.drawImage(img, 0, 0); - Dropzone.SUCCESS = "success"; + var _ctx$getImageData = ctx.getImageData(1, 0, 1, ih), + data = _ctx$getImageData.data; + // search image edge pixel position in case it is squashed vertically. - /* - - Bugfix for iOS 6 and 7 - Source: http://stackoverflow.com/questions/11929099/html5-canvas-drawimage-ratio-bug-ios - based on the work of https://github.com/stomita/ios-imagefile-megapixel - */ - detectVerticalSquash = function(img) { - var alpha, canvas, ctx, data, ey, ih, iw, py, ratio, sy; - iw = img.naturalWidth; - ih = img.naturalHeight; - canvas = document.createElement("canvas"); - canvas.width = 1; - canvas.height = ih; - ctx = canvas.getContext("2d"); - ctx.drawImage(img, 0, 0); - data = ctx.getImageData(0, 0, 1, ih).data; - sy = 0; - ey = ih; - py = ih; - while (py > sy) { - alpha = data[(py - 1) * 4 + 3]; - if (alpha === 0) { - ey = py; - } else { - sy = py; - } - py = (ey + sy) >> 1; - } - ratio = py / ih; - if (ratio === 0) { - return 1; + var sy = 0; + var ey = ih; + var py = ih; + while (py > sy) { + var alpha = data[(py - 1) * 4 + 3]; + + if (alpha === 0) { + ey = py; } else { - return ratio; + sy = py; } - }; - drawImageIOSFix = function(ctx, img, sx, sy, sw, sh, dx, dy, dw, dh) { - var vertSquashRatio; - vertSquashRatio = detectVerticalSquash(img); - return ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh / vertSquashRatio); - }; + py = ey + sy >> 1; + } + var ratio = py / ih; + if (ratio === 0) { + return 1; + } else { + return ratio; + } +}; + +// A replacement for context.drawImage +// (args are for source and destination). +var drawImageIOSFix = function drawImageIOSFix(ctx, img, sx, sy, sw, sh, dx, dy, dw, dh) { + var vertSquashRatio = detectVerticalSquash(img); + return ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh / vertSquashRatio); +}; + +// Based on MinifyJpeg +// Source: http://www.perry.cz/files/ExifRestorer.js +// http://elicon.blog57.fc2.com/blog-entry-206.html + +var ExifRestore = function () { + function ExifRestore() { + _classCallCheck(this, ExifRestore); + } - /* - * contentloaded.js - * - * Author: Diego Perini (diego.perini at gmail.com) - * Summary: cross-browser wrapper for DOMContentLoaded - * Updated: 20101020 - * License: MIT - * Version: 1.2 - * - * URL: - * http://javascript.nwbox.com/ContentLoaded/ - * http://javascript.nwbox.com/ContentLoaded/MIT-LICENSE - */ - - contentLoaded = function(win, fn) { - var add, doc, done, init, poll, pre, rem, root, top; - done = false; - top = true; - doc = win.document; - root = doc.documentElement; - add = (doc.addEventListener ? "addEventListener" : "attachEvent"); - rem = (doc.addEventListener ? "removeEventListener" : "detachEvent"); - pre = (doc.addEventListener ? "" : "on"); - init = function(e) { - if (e.type === "readystatechange" && doc.readyState !== "complete") { - return; + _createClass(ExifRestore, null, [{ + key: "initClass", + value: function initClass() { + this.KEY_STR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + } + }, { + key: "encode64", + value: function encode64(input) { + var output = ''; + var chr1 = undefined; + var chr2 = undefined; + var chr3 = ''; + var enc1 = undefined; + var enc2 = undefined; + var enc3 = undefined; + var enc4 = ''; + var i = 0; + while (true) { + chr1 = input[i++]; + chr2 = input[i++]; + chr3 = input[i++]; + enc1 = chr1 >> 2; + enc2 = (chr1 & 3) << 4 | chr2 >> 4; + enc3 = (chr2 & 15) << 2 | chr3 >> 6; + enc4 = chr3 & 63; + if (isNaN(chr2)) { + enc3 = enc4 = 64; + } else if (isNaN(chr3)) { + enc4 = 64; + } + output = output + this.KEY_STR.charAt(enc1) + this.KEY_STR.charAt(enc2) + this.KEY_STR.charAt(enc3) + this.KEY_STR.charAt(enc4); + chr1 = chr2 = chr3 = ''; + enc1 = enc2 = enc3 = enc4 = ''; + if (!(i < input.length)) { + break; + } } - (e.type === "load" ? win : doc)[rem](pre + e.type, init, false); - if (!done && (done = true)) { - return fn.call(win, e.type || e); + return output; + } + }, { + key: "restore", + value: function restore(origFileBase64, resizedFileBase64) { + if (!origFileBase64.match('data:image/jpeg;base64,')) { + return resizedFileBase64; + } + var rawImage = this.decode64(origFileBase64.replace('data:image/jpeg;base64,', '')); + var segments = this.slice2Segments(rawImage); + var image = this.exifManipulation(resizedFileBase64, segments); + return "data:image/jpeg;base64," + this.encode64(image); + } + }, { + key: "exifManipulation", + value: function exifManipulation(resizedFileBase64, segments) { + var exifArray = this.getExifArray(segments); + var newImageArray = this.insertExif(resizedFileBase64, exifArray); + var aBuffer = new Uint8Array(newImageArray); + return aBuffer; + } + }, { + key: "getExifArray", + value: function getExifArray(segments) { + var seg = undefined; + var x = 0; + while (x < segments.length) { + seg = segments[x]; + if (seg[0] === 255 & seg[1] === 225) { + return seg; + } + x++; } - }; - poll = function() { - var e; - try { - root.doScroll("left"); - } catch (_error) { - e = _error; - setTimeout(poll, 50); - return; + return []; + } + }, { + key: "insertExif", + value: function insertExif(resizedFileBase64, exifArray) { + var imageData = resizedFileBase64.replace('data:image/jpeg;base64,', ''); + var buf = this.decode64(imageData); + var separatePoint = buf.indexOf(255, 3); + var mae = buf.slice(0, separatePoint); + var ato = buf.slice(separatePoint); + var array = mae; + array = array.concat(exifArray); + array = array.concat(ato); + return array; + } + }, { + key: "slice2Segments", + value: function slice2Segments(rawImageArray) { + var head = 0; + var segments = []; + while (true) { + var length; + if (rawImageArray[head] === 255 & rawImageArray[head + 1] === 218) { + break; + } + if (rawImageArray[head] === 255 & rawImageArray[head + 1] === 216) { + head += 2; + } else { + length = rawImageArray[head + 2] * 256 + rawImageArray[head + 3]; + var endPoint = head + length + 2; + var seg = rawImageArray.slice(head, endPoint); + segments.push(seg); + head = endPoint; + } + if (head > rawImageArray.length) { + break; + } } - return init("poll"); - }; - if (doc.readyState !== "complete") { - if (doc.createEventObject && root.doScroll) { - try { - top = !win.frameElement; - } catch (_error) {} - if (top) { - poll(); + return segments; + } + }, { + key: "decode64", + value: function decode64(input) { + var output = ''; + var chr1 = undefined; + var chr2 = undefined; + var chr3 = ''; + var enc1 = undefined; + var enc2 = undefined; + var enc3 = undefined; + var enc4 = ''; + var i = 0; + var buf = []; + // remove all characters that are not A-Z, a-z, 0-9, +, /, or = + var base64test = /[^A-Za-z0-9\+\/\=]/g; + if (base64test.exec(input)) { + console.warn('There were invalid base64 characters in the input text.\nValid base64 characters are A-Z, a-z, 0-9, \'+\', \'/\',and \'=\'\nExpect errors in decoding.'); + } + input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ''); + while (true) { + enc1 = this.KEY_STR.indexOf(input.charAt(i++)); + enc2 = this.KEY_STR.indexOf(input.charAt(i++)); + enc3 = this.KEY_STR.indexOf(input.charAt(i++)); + enc4 = this.KEY_STR.indexOf(input.charAt(i++)); + chr1 = enc1 << 2 | enc2 >> 4; + chr2 = (enc2 & 15) << 4 | enc3 >> 2; + chr3 = (enc3 & 3) << 6 | enc4; + buf.push(chr1); + if (enc3 !== 64) { + buf.push(chr2); + } + if (enc4 !== 64) { + buf.push(chr3); + } + chr1 = chr2 = chr3 = ''; + enc1 = enc2 = enc3 = enc4 = ''; + if (!(i < input.length)) { + break; } } - doc[add](pre + "DOMContentLoaded", init, false); - doc[add](pre + "readystatechange", init, false); - return win[add](pre + "load", init, false); + return buf; + } + }]); + + return ExifRestore; +}(); + +ExifRestore.initClass(); + +/* + * contentloaded.js + * + * Author: Diego Perini (diego.perini at gmail.com) + * Summary: cross-browser wrapper for DOMContentLoaded + * Updated: 20101020 + * License: MIT + * Version: 1.2 + * + * URL: + * http://javascript.nwbox.com/ContentLoaded/ + * http://javascript.nwbox.com/ContentLoaded/MIT-LICENSE + */ + +// @win window reference +// @fn function reference +var contentLoaded = function contentLoaded(win, fn) { + var done = false; + var top = true; + var doc = win.document; + var root = doc.documentElement; + var add = doc.addEventListener ? "addEventListener" : "attachEvent"; + var rem = doc.addEventListener ? "removeEventListener" : "detachEvent"; + var pre = doc.addEventListener ? "" : "on"; + var init = function init(e) { + if (e.type === "readystatechange" && doc.readyState !== "complete") { + return; + } + (e.type === "load" ? win : doc)[rem](pre + e.type, init, false); + if (!done && (done = true)) { + return fn.call(win, e.type || e); } }; - Dropzone._autoDiscoverFunction = function() { - if (Dropzone.autoDiscover) { - return Dropzone.discover(); + var poll = function poll() { + try { + root.doScroll("left"); + } catch (e) { + setTimeout(poll, 50); + return; } + return init("poll"); }; - contentLoaded(window, Dropzone._autoDiscoverFunction); + if (doc.readyState !== "complete") { + if (doc.createEventObject && root.doScroll) { + try { + top = !win.frameElement; + } catch (error) {} + if (top) { + poll(); + } + } + doc[add](pre + "DOMContentLoaded", init, false); + doc[add](pre + "readystatechange", init, false); + return win[add](pre + "load", init, false); + } +}; -}).call(this); +// As a single function to be able to write tests. +Dropzone._autoDiscoverFunction = function () { + if (Dropzone.autoDiscover) { + return Dropzone.discover(); + } +}; +contentLoaded(window, Dropzone._autoDiscoverFunction); + +function __guard__(value, transform) { + return typeof value !== 'undefined' && value !== null ? transform(value) : undefined; +} +function __guardMethod__(obj, methodName, transform) { + if (typeof obj !== 'undefined' && obj !== null && typeof obj[methodName] === 'function') { + return transform(obj, methodName); + } else { + return undefined; + } +} \ No newline at end of file From 5687f9b8b46e6f1197e88a63e9e51ebbf8f4da18 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Wed, 11 Sep 2019 20:02:43 +1000 Subject: [PATCH 003/157] Recompile assets --- modules/backend/assets/css/october.css | 24 +- modules/backend/assets/js/october-min.js | 306 +++++++++++------- .../codeeditor/assets/css/codeeditor.css | 4 +- .../fileupload/assets/css/fileupload.css | 2 +- .../repeater/assets/css/repeater.css | 6 +- .../richeditor/assets/css/richeditor.css | 4 +- modules/system/assets/css/styles.css | 4 +- modules/system/assets/ui/storm.css | 70 ++-- 8 files changed, 243 insertions(+), 177 deletions(-) diff --git a/modules/backend/assets/css/october.css b/modules/backend/assets/css/october.css index f305909983..29ead2b350 100644 --- a/modules/backend/assets/css/october.css +++ b/modules/backend/assets/css/october.css @@ -169,9 +169,9 @@ html.mobile .control-scrollbar {overflow:auto;-webkit-overflow-scrolling:touch} .control-filelist ul li.group >h4 a:after, .control-filelist ul li.group >div.group >h4 a:after {width:10px;height:10px;display:block;position:absolute;top:1px} .control-filelist ul li.group >h4 a:after, -.control-filelist ul li.group >div.group >h4 a:after {left:33px;top:9px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f07b";color:#a1aab1;font-size:16px} +.control-filelist ul li.group >div.group >h4 a:after {left:33px;top:9px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f07b";color:#a1aab1;font-size:16px} .control-filelist ul li.group >h4 a:before, -.control-filelist ul li.group >div.group >h4 a:before {left:20px;top:9px;color:#cfcfcf;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f0da";-webkit-transform:rotate(90deg) translate(5px,0);-ms-transform:rotate(90deg) translate(5px,0);transform:rotate(90deg) translate(5px,0);-webkit-transition:all 0.1s ease;transition:all 0.1s ease} +.control-filelist ul li.group >div.group >h4 a:before {left:20px;top:9px;color:#cfcfcf;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f0da";-webkit-transform:rotate(90deg) translate(5px,0);-ms-transform:rotate(90deg) translate(5px,0);transform:rotate(90deg) translate(5px,0);-webkit-transition:all 0.1s ease;transition:all 0.1s ease} .control-filelist ul li.group >ul >li >a {padding-left:52px} .control-filelist ul li.group >ul >li.group {padding-left:20px} .control-filelist ul li.group >ul >li.group >ul >li >a {padding-left:324px;margin-left:-270px} @@ -276,10 +276,10 @@ html.mobile .control-scrollbar {overflow:auto;-webkit-overflow-scrolling:touch} .control-treelist >ol >li >div.record:before {display:none} .control-treelist li {margin:0;padding:0} .control-treelist li >div.record {margin:0;font-size:12px;margin-bottom:5px;position:relative;display:block} -.control-treelist li >div.record:before {color:#bdc3c7;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f111";font-size:6px;position:absolute;left:-18px;top:11px} +.control-treelist li >div.record:before {color:#bdc3c7;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f111";font-size:6px;position:absolute;left:-18px;top:11px} .control-treelist li >div.record >a.move {display:inline-block;padding:7px 0 7px 10px;text-decoration:none;color:#bdc3c7} .control-treelist li >div.record >a.move:hover {color:#4ea5e0} -.control-treelist li >div.record >a.move:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f0c9"} +.control-treelist li >div.record >a.move:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f0c9"} .control-treelist li >div.record >span {color:#666;display:inline-block;padding:7px 15px 7px 5px} .control-treelist li.dragged {position:absolute;z-index:2000;width:auto !important;height:auto !important} .control-treelist li.dragged >div.record {opacity:0.5;filter:alpha(opacity=50);background:#4ea5e0 !important} @@ -287,7 +287,7 @@ html.mobile .control-scrollbar {overflow:auto;-webkit-overflow-scrolling:touch} .control-treelist li.dragged >div.record >span {color:white} .control-treelist li.dragged >div.record:before {display:none} .control-treelist li.placeholder {display:inline-block;position:relative;background:#4ea5e0 !important;height:25px;margin-bottom:5px} -.control-treelist li.placeholder:before {display:block;position:absolute;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f053";color:#d35714;left:-10px;top:8px;z-index:2000} +.control-treelist li.placeholder:before {display:block;position:absolute;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f053";color:#d35714;left:-10px;top:8px;z-index:2000} .control-treeview {margin-bottom:40px} .control-treeview ol {margin:0;padding:0;list-style:none;background:#fff} .control-treeview ol >li {-webkit-transition:width 1s;transition:width 1s} @@ -296,9 +296,9 @@ html.mobile .control-scrollbar {overflow:auto;-webkit-overflow-scrolling:touch} .control-treeview ol >li >div:before {content:' ';background-image:url(../images/treeview-icons.png);background-position:0 -28px;background-repeat:no-repeat;background-size:42px auto;position:absolute;width:21px;height:22px;left:28px;top:15px} .control-treeview ol >li >div span.comment {display:block;font-weight:400;color:#95a5a6;font-size:13px;margin-top:2px;overflow:hidden;text-overflow:ellipsis} .control-treeview ol >li >div >span.expand {font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;display:none;position:absolute;width:20px;height:20px;top:19px;left:2px;cursor:pointer;color:#bdc3c7;-webkit-transition:transform 0.1s ease;transition:transform 0.1s ease} -.control-treeview ol >li >div >span.expand:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f0da";line-height:100%;font-size:15px;position:relative;left:8px;top:2px} +.control-treeview ol >li >div >span.expand:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f0da";line-height:100%;font-size:15px;position:relative;left:8px;top:2px} .control-treeview ol >li >div >span.drag-handle {font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;-webkit-transition:opacity 0.4s;transition:opacity 0.4s;position:absolute;right:9px;bottom:0;width:18px;height:19px;cursor:move;color:#bdc3c7;opacity:0;filter:alpha(opacity=0)} -.control-treeview ol >li >div >span.drag-handle:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f0c9";font-size:18px} +.control-treeview ol >li >div >span.drag-handle:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f0c9";font-size:18px} .control-treeview ol >li >div span.borders {font-size:0} .control-treeview ol >li >div >ul.submenu {position:absolute;left:20px;bottom:-36.9px;padding:0;list-style:none;z-index:200;height:37px;display:none;margin-left:15px;background:transparent url(../images/treeview-submenu-tabs.png) repeat-x left -39px} .control-treeview ol >li >div >ul.submenu:before, @@ -449,7 +449,7 @@ body.dragging .control-treeview.treeview-light ol.dragging ol >li >div {backgrou .sidenav-tree ul.top-level >li[data-status=collapsed] ul {display:none} .sidenav-tree ul.top-level >li >div.group {position:relative} .sidenav-tree ul.top-level >li >div.group h3 {background:rgba(0,0,0,0.15);color:#ecf0f1;text-transform:uppercase;font-size:15px;padding:15px 15px 15px 40px;margin:0;position:relative;cursor:pointer;font-weight:400} -.sidenav-tree ul.top-level >li >div.group h3:before {display:block;position:absolute;width:10px;height:10px;left:16px;top:15px;color:#cfcfcf;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f105";-webkit-transform:rotate(90deg) translate(5px,-3px);-ms-transform:rotate(90deg) translate(5px,-3px);transform:rotate(90deg) translate(5px,-3px);-webkit-transition:all 0.1s ease;transition:all 0.1s ease;font-size:16px} +.sidenav-tree ul.top-level >li >div.group h3:before {display:block;position:absolute;width:10px;height:10px;left:16px;top:15px;color:#cfcfcf;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f105";-webkit-transform:rotate(90deg) translate(5px,-3px);-ms-transform:rotate(90deg) translate(5px,-3px);transform:rotate(90deg) translate(5px,-3px);-webkit-transition:all 0.1s ease;transition:all 0.1s ease;font-size:16px} .sidenav-tree ul.top-level >li >div.group:before, .sidenav-tree ul.top-level >li >div.group:after {content:'';display:block;width:0;height:0;border-left:7.5px solid transparent;border-right:7.5px solid transparent;border-top:8px solid #34495e;border-bottom-width:0;position:absolute;left:15px;bottom:-8px;z-index:101} .sidenav-tree ul.top-level >li >div.group:after {content:'';display:block;width:0;height:0;border-left:7.5px solid transparent;border-right:7.5px solid transparent;border-top:8px solid rgba(0,0,0,0.15);border-bottom-width:0} @@ -495,7 +495,7 @@ div.panel >label {margin-bottom:5px} div.panel .nav.selector-group {margin:0 -20px 20px -20px} ul.tree-path {list-style:none;padding:0;margin-bottom:0} ul.tree-path li {display:inline-block;margin-right:1px;font-size:13px} -ul.tree-path li:after {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f105";display:inline-block;font-size:13px;margin-left:5px;position:relative;top:1px;color:#95a5a6} +ul.tree-path li:after {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f105";display:inline-block;font-size:13px;margin-left:5px;position:relative;top:1px;color:#95a5a6} ul.tree-path li:last-child a {cursor:default} ul.tree-path li:last-child:after {display:none} ul.tree-path li.go-up {font-size:12px;margin-right:7px} @@ -778,7 +778,7 @@ nav#layout-mainmenu.navbar-mode-collapse .menu-toggle {display:inline-block;colo .mainmenu-collapsed >div ul li a i {line-height:1;font-size:30px;vertical-align:middle} .mainmenu-collapsed >div ul li a img.svg-icon {height:30px;width:30px;position:relative;top:0} .mainmenu-collapsed .scroll-marker {position:absolute;left:0;width:100%;height:10px;display:none} -.mainmenu-collapsed .scroll-marker:after {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f141";display:block;position:absolute;left:50%;margin-left:-3px;top:0;height:9px;font-size:10px;color:rgba(255,255,255,0.6)} +.mainmenu-collapsed .scroll-marker:after {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f141";display:block;position:absolute;left:50%;margin-left:-3px;top:0;height:9px;font-size:10px;color:rgba(255,255,255,0.6)} .mainmenu-collapsed .scroll-marker.before {top:0} .mainmenu-collapsed .scroll-marker.after {bottom:3px} .mainmenu-collapsed .scroll-marker.after:after {top:2px} @@ -940,7 +940,7 @@ body.breadcrumb-fancy .control-breadcrumb li:last-child:before, .fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li[data-modified] span.tab-close i, .fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li[data-modified] span.tab-close i {top:5px;font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0} .fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li[data-modified] span.tab-close i:before, -.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li[data-modified] span.tab-close i:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f111";font-size:9px} +.fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li[data-modified] span.tab-close i:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f111";font-size:9px} .fancy-layout .control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li:first-child, .fancy-layout.control-tabs.master-tabs >div >div.tabs-container >ul.nav-tabs >li:first-child {margin-left:0} .fancy-layout .control-tabs.master-tabs[data-closable] >div >div.tabs-container >ul.nav-tabs >li a >span.title, @@ -1112,4 +1112,4 @@ html.gecko .fancy-layout .control-tabs.secondary-tabs >div >ul.nav-tabs >li.acti .flyout-toggle i {margin:7px 0 0 6px;display:inline-block} .flyout-toggle:hover i {color:#fff} body.flyout-visible {overflow:hidden} -body.flyout-visible .flyout-overlay {background-color:rgba(0,0,0,0.3)} +body.flyout-visible .flyout-overlay {background-color:rgba(0,0,0,0.3)} \ No newline at end of file diff --git a/modules/backend/assets/js/october-min.js b/modules/backend/assets/js/october-min.js index 3820594b4c..e053435ccc 100644 --- a/modules/backend/assets/js/october-min.js +++ b/modules/backend/assets/js/october-min.js @@ -36,140 +36,206 @@ return(document.cookie=[encode(key),'=',stringifyCookieValue(value),options.expi var result=key?undefined:{};var cookies=document.cookie?document.cookie.split('; '):[];for(var i=0,l=cookies.length;i1?_len-1:0),_key=1;_key<_len;_key++){args[_key-1]=arguments[_key];} +for(var _iterator=callbacks,_isArray=true,_i=0,_iterator=_isArray?_iterator:_iterator[Symbol.iterator]();;){var _ref;if(_isArray){if(_i>=_iterator.length)break;_ref=_iterator[_i++];}else{_i=_iterator.next();if(_i.done)break;_ref=_i.value;} +var callback=_ref;callback.apply(this,args);}} +return this;}},{key:"off",value:function off(event,fn){if(!this._callbacks||arguments.length===0){this._callbacks={};return this;} +var callbacks=this._callbacks[event];if(!callbacks){return this;} if(arguments.length===1){delete this._callbacks[event];return this;} -for(i=_i=0,_len=callbacks.length;_i<_len;i=++_i){callback=callbacks[i];if(callback===fn){callbacks.splice(i,1);break;}} -return this;};return Emitter;})();Dropzone=(function(_super){var extend,resolveOption;__extends(Dropzone,_super);Dropzone.prototype.Emitter=Emitter;Dropzone.prototype.events=["drop","dragstart","dragend","dragenter","dragover","dragleave","addedfile","removedfile","thumbnail","error","errormultiple","processing","processingmultiple","uploadprogress","totaluploadprogress","sending","sendingmultiple","success","successmultiple","canceled","canceledmultiple","complete","completemultiple","reset","maxfilesexceeded","maxfilesreached","queuecomplete"];Dropzone.prototype.defaultOptions={url:null,method:"post",withCredentials:false,parallelUploads:2,uploadMultiple:false,maxFilesize:256,paramName:"file",createImageThumbnails:true,maxThumbnailFilesize:10,thumbnailWidth:120,thumbnailHeight:120,filesizeBase:1000,maxFiles:null,filesizeBase:1000,params:{},clickable:true,ignoreHiddenFiles:true,acceptedFiles:null,acceptedMimeTypes:null,autoProcessQueue:true,autoQueue:true,addRemoveLinks:false,previewsContainer:null,capture:null,dictDefaultMessage:"Drop files here to upload",dictFallbackMessage:"Your browser does not support drag'n'drop file uploads.",dictFallbackText:"Please use the fallback form below to upload your files like in the olden days.",dictFileTooBig:"File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.",dictInvalidFileType:"You can't upload files of this type.",dictResponseError:"Server responded with {{statusCode}} code.",dictCancelUpload:"Cancel upload",dictCancelUploadConfirmation:"Are you sure you want to cancel this upload?",dictRemoveFile:"Remove file",dictRemoveFileConfirmation:null,dictMaxFilesExceeded:"You can not upload any more files.",accept:function(file,done){return done();},init:function(){return noop;},forceFallback:false,fallback:function(){var child,messageElement,span,_i,_len,_ref;this.element.className=""+this.element.className+" dz-browser-not-supported";_ref=this.element.getElementsByTagName("div");for(_i=0,_len=_ref.length;_i<_len;_i++){child=_ref[_i];if(/(^| )dz-message($| )/.test(child.className)){messageElement=child;child.className="dz-message";continue;}} +for(var i=0;i=_iterator2.length)break;_ref2=_iterator2[_i2++];}else{_i2=_iterator2.next();if(_i2.done)break;_ref2=_i2.value;} +var child=_ref2;if(/(^| )dz-message($| )/.test(child.className)){messageElement=child;child.className="dz-message";break;}} if(!messageElement){messageElement=Dropzone.createElement("
");this.element.appendChild(messageElement);} -span=messageElement.getElementsByTagName("span")[0];if(span){span.textContent=this.options.dictFallbackMessage;} -return this.element.appendChild(this.getFallbackForm());},resize:function(file){var info,srcRatio,trgRatio;info={srcX:0,srcY:0,srcWidth:file.width,srcHeight:file.height};srcRatio=file.width/file.height;info.optWidth=this.options.thumbnailWidth;info.optHeight=this.options.thumbnailHeight;if((info.optWidth==null)&&(info.optHeight==null)){info.optWidth=info.srcWidth;info.optHeight=info.srcHeight;}else if(info.optWidth==null){info.optWidth=srcRatio*info.optHeight;}else if(info.optHeight==null){info.optHeight=(1/srcRatio)*info.optWidth;} -trgRatio=info.optWidth/info.optHeight;if(file.heighttrgRatio){info.srcHeight=file.height;info.srcWidth=info.srcHeight*trgRatio;}else{info.srcWidth=file.width;info.srcHeight=info.srcWidth/trgRatio;}} -info.srcX=(file.width-info.srcWidth)/2;info.srcY=(file.height-info.srcHeight)/2;return info;},drop:function(e){return this.element.classList.remove("dz-drag-hover");},dragstart:noop,dragend:function(e){return this.element.classList.remove("dz-drag-hover");},dragenter:function(e){return this.element.classList.add("dz-drag-hover");},dragover:function(e){return this.element.classList.add("dz-drag-hover");},dragleave:function(e){return this.element.classList.remove("dz-drag-hover");},paste:noop,reset:function(){return this.element.classList.remove("dz-started");},addedfile:function(file){var node,removeFileEvent,removeLink,_i,_j,_k,_len,_len1,_len2,_ref,_ref1,_ref2,_results;if(this.element===this.previewsContainer){this.element.classList.add("dz-started");} -if(this.previewsContainer){file.previewElement=Dropzone.createElement(this.options.previewTemplate.trim());file.previewTemplate=file.previewElement;this.previewsContainer.appendChild(file.previewElement);_ref=file.previewElement.querySelectorAll("[data-dz-name]");for(_i=0,_len=_ref.length;_i<_len;_i++){node=_ref[_i];node.textContent=file.name;} -_ref1=file.previewElement.querySelectorAll("[data-dz-size]");for(_j=0,_len1=_ref1.length;_j<_len1;_j++){node=_ref1[_j];node.innerHTML=this.filesize(file.size);} +var span=messageElement.getElementsByTagName("span")[0];if(span){if(span.textContent!=null){span.textContent=this.options.dictFallbackMessage;}else if(span.innerText!=null){span.innerText=this.options.dictFallbackMessage;}} +return this.element.appendChild(this.getFallbackForm());},resize:function resize(file,width,height,resizeMethod){var info={srcX:0,srcY:0,srcWidth:file.width,srcHeight:file.height};var srcRatio=file.width/file.height;if(width==null&&height==null){width=info.srcWidth;height=info.srcHeight;}else if(width==null){width=height*srcRatio;}else if(height==null){height=width/srcRatio;} +width=Math.min(width,info.srcWidth);height=Math.min(height,info.srcHeight);var trgRatio=width/height;if(info.srcWidth>width||info.srcHeight>height){if(resizeMethod==='crop'){if(srcRatio>trgRatio){info.srcHeight=file.height;info.srcWidth=info.srcHeight*trgRatio;}else{info.srcWidth=file.width;info.srcHeight=info.srcWidth/trgRatio;}}else if(resizeMethod==='contain'){if(srcRatio>trgRatio){height=width/srcRatio;}else{width=height*srcRatio;}}else{throw new Error("Unknown resizeMethod '"+resizeMethod+"'");}} +info.srcX=(file.width-info.srcWidth)/2;info.srcY=(file.height-info.srcHeight)/2;info.trgWidth=width;info.trgHeight=height;return info;},transformFile:function transformFile(file,done){if((this.options.resizeWidth||this.options.resizeHeight)&&file.type.match(/image.*/)){return this.resizeImage(file,this.options.resizeWidth,this.options.resizeHeight,this.options.resizeMethod,done);}else{return done(file);}},previewTemplate:"
\n
\n
\n
\n
\n
\n
\n
\n
\n \n Check\n \n \n \n \n \n
\n
\n \n Error\n \n \n \n \n \n \n \n
\n
",drop:function drop(e){return this.element.classList.remove("dz-drag-hover");},dragstart:function dragstart(e){},dragend:function dragend(e){return this.element.classList.remove("dz-drag-hover");},dragenter:function dragenter(e){return this.element.classList.add("dz-drag-hover");},dragover:function dragover(e){return this.element.classList.add("dz-drag-hover");},dragleave:function dragleave(e){return this.element.classList.remove("dz-drag-hover");},paste:function paste(e){},reset:function reset(){return this.element.classList.remove("dz-started");},addedfile:function addedfile(file){var _this2=this;if(this.element===this.previewsContainer){this.element.classList.add("dz-started");} +if(this.previewsContainer){file.previewElement=Dropzone.createElement(this.options.previewTemplate.trim());file.previewTemplate=file.previewElement;this.previewsContainer.appendChild(file.previewElement);for(var _iterator3=file.previewElement.querySelectorAll("[data-dz-name]"),_isArray3=true,_i3=0,_iterator3=_isArray3?_iterator3:_iterator3[Symbol.iterator]();;){var _ref3;if(_isArray3){if(_i3>=_iterator3.length)break;_ref3=_iterator3[_i3++];}else{_i3=_iterator3.next();if(_i3.done)break;_ref3=_i3.value;} +var node=_ref3;node.textContent=file.name;} +for(var _iterator4=file.previewElement.querySelectorAll("[data-dz-size]"),_isArray4=true,_i4=0,_iterator4=_isArray4?_iterator4:_iterator4[Symbol.iterator]();;){if(_isArray4){if(_i4>=_iterator4.length)break;node=_iterator4[_i4++];}else{_i4=_iterator4.next();if(_i4.done)break;node=_i4.value;} +node.innerHTML=this.filesize(file.size);} if(this.options.addRemoveLinks){file._removeLink=Dropzone.createElement(""+this.options.dictRemoveFile+"");file.previewElement.appendChild(file._removeLink);} -removeFileEvent=(function(_this){return function(e){e.preventDefault();e.stopPropagation();if(file.status===Dropzone.UPLOADING){return Dropzone.confirm(_this.options.dictCancelUploadConfirmation,function(){return _this.removeFile(file);});}else{if(_this.options.dictRemoveFileConfirmation){return Dropzone.confirm(_this.options.dictRemoveFileConfirmation,function(){return _this.removeFile(file);});}else{return _this.removeFile(file);}}};})(this);_ref2=file.previewElement.querySelectorAll("[data-dz-remove]");_results=[];for(_k=0,_len2=_ref2.length;_k<_len2;_k++){removeLink=_ref2[_k];_results.push(removeLink.addEventListener("click",removeFileEvent));} -return _results;}},removedfile:function(file){var _ref;if(file.previewElement){if((_ref=file.previewElement)!=null){_ref.parentNode.removeChild(file.previewElement);}} -return this._updateMaxFilesReachedClass();},thumbnail:function(file,dataUrl){var thumbnailElement,_i,_len,_ref;if(file.previewElement){file.previewElement.classList.remove("dz-file-preview");_ref=file.previewElement.querySelectorAll("[data-dz-thumbnail]");for(_i=0,_len=_ref.length;_i<_len;_i++){thumbnailElement=_ref[_i];thumbnailElement.alt=file.name;thumbnailElement.src=dataUrl;} -return setTimeout(((function(_this){return function(){return file.previewElement.classList.add("dz-image-preview");};})(this)),1);}},error:function(file,message){var node,_i,_len,_ref,_results;if(file.previewElement){file.previewElement.classList.add("dz-error");if(typeof message!=="String"&&message.error){message=message.error;} -_ref=file.previewElement.querySelectorAll("[data-dz-errormessage]");_results=[];for(_i=0,_len=_ref.length;_i<_len;_i++){node=_ref[_i];_results.push(node.textContent=message);} -return _results;}},errormultiple:noop,processing:function(file){if(file.previewElement){file.previewElement.classList.add("dz-processing");if(file._removeLink){return file._removeLink.textContent=this.options.dictCancelUpload;}}},processingmultiple:noop,uploadprogress:function(file,progress,bytesSent){var node,_i,_len,_ref,_results;if(file.previewElement){_ref=file.previewElement.querySelectorAll("[data-dz-uploadprogress]");_results=[];for(_i=0,_len=_ref.length;_i<_len;_i++){node=_ref[_i];if(node.nodeName==='PROGRESS'){_results.push(node.value=progress);}else{_results.push(node.style.width=""+progress+"%");}} -return _results;}},totaluploadprogress:noop,sending:noop,sendingmultiple:noop,success:function(file){if(file.previewElement){return file.previewElement.classList.add("dz-success");}},successmultiple:noop,canceled:function(file){return this.emit("error",file,"Upload canceled.");},canceledmultiple:noop,complete:function(file){if(file._removeLink){file._removeLink.textContent=this.options.dictRemoveFile;} -if(file.previewElement){return file.previewElement.classList.add("dz-complete");}},completemultiple:noop,maxfilesexceeded:noop,maxfilesreached:noop,queuecomplete:noop,previewTemplate:"
\n
\n
\n
\n
\n
\n
\n
\n
\n \n Check\n \n \n \n \n \n
\n
\n \n Error\n \n \n \n \n \n \n \n
\n
"};extend=function(){var key,object,objects,target,val,_i,_len;target=arguments[0],objects=2<=arguments.length?__slice.call(arguments,1):[];for(_i=0,_len=objects.length;_i<_len;_i++){object=objects[_i];for(key in object){val=object[key];target[key]=val;}} -return target;};function Dropzone(element,options){var elementOptions,fallback,_ref;this.element=element;this.version=Dropzone.version;this.defaultOptions.previewTemplate=this.defaultOptions.previewTemplate.replace(/\n*/g,"");this.clickableElements=[];this.listeners=[];this.files=[];if(typeof this.element==="string"){this.element=document.querySelector(this.element);} -if(!(this.element&&(this.element.nodeType!=null))){throw new Error("Invalid dropzone element.");} -if(this.element.dropzone){throw new Error("Dropzone already attached.");} -Dropzone.instances.push(this);this.element.dropzone=this;elementOptions=(_ref=Dropzone.optionsForElement(this.element))!=null?_ref:{};this.options=extend({},this.defaultOptions,elementOptions,options!=null?options:{});if(this.options.forceFallback||!Dropzone.isBrowserSupported()){return this.options.fallback.call(this);} -if(this.options.url==null){this.options.url=this.element.getAttribute("action");} -if(!this.options.url){throw new Error("No URL provided.");} -if(this.options.acceptedFiles&&this.options.acceptedMimeTypes){throw new Error("You can't provide both 'acceptedFiles' and 'acceptedMimeTypes'. 'acceptedMimeTypes' is deprecated.");} -if(this.options.acceptedMimeTypes){this.options.acceptedFiles=this.options.acceptedMimeTypes;delete this.options.acceptedMimeTypes;} -this.options.method=this.options.method.toUpperCase();if((fallback=this.getExistingFallback())&&fallback.parentNode){fallback.parentNode.removeChild(fallback);} -if(this.options.previewsContainer!==false){if(this.options.previewsContainer){this.previewsContainer=Dropzone.getElement(this.options.previewsContainer,"previewsContainer");}else{this.previewsContainer=this.element;}} -if(this.options.clickable){if(this.options.clickable===true){this.clickableElements=[this.element];}else{this.clickableElements=Dropzone.getElements(this.options.clickable,"clickable");}} -this.init();} -Dropzone.prototype.getAcceptedFiles=function(){var file,_i,_len,_ref,_results;_ref=this.files;_results=[];for(_i=0,_len=_ref.length;_i<_len;_i++){file=_ref[_i];if(file.accepted){_results.push(file);}} -return _results;};Dropzone.prototype.getRejectedFiles=function(){var file,_i,_len,_ref,_results;_ref=this.files;_results=[];for(_i=0,_len=_ref.length;_i<_len;_i++){file=_ref[_i];if(!file.accepted){_results.push(file);}} -return _results;};Dropzone.prototype.getFilesWithStatus=function(status){var file,_i,_len,_ref,_results;_ref=this.files;_results=[];for(_i=0,_len=_ref.length;_i<_len;_i++){file=_ref[_i];if(file.status===status){_results.push(file);}} -return _results;};Dropzone.prototype.getQueuedFiles=function(){return this.getFilesWithStatus(Dropzone.QUEUED);};Dropzone.prototype.getUploadingFiles=function(){return this.getFilesWithStatus(Dropzone.UPLOADING);};Dropzone.prototype.getActiveFiles=function(){var file,_i,_len,_ref,_results;_ref=this.files;_results=[];for(_i=0,_len=_ref.length;_i<_len;_i++){file=_ref[_i];if(file.status===Dropzone.UPLOADING||file.status===Dropzone.QUEUED){_results.push(file);}} -return _results;};Dropzone.prototype.init=function(){var eventName,noPropagation,setupHiddenFileInput,_i,_len,_ref,_ref1;if(this.element.tagName==="form"){this.element.setAttribute("enctype","multipart/form-data");} +var removeFileEvent=function removeFileEvent(e){e.preventDefault();e.stopPropagation();if(file.status===Dropzone.UPLOADING){return Dropzone.confirm(_this2.options.dictCancelUploadConfirmation,function(){return _this2.removeFile(file);});}else{if(_this2.options.dictRemoveFileConfirmation){return Dropzone.confirm(_this2.options.dictRemoveFileConfirmation,function(){return _this2.removeFile(file);});}else{return _this2.removeFile(file);}}};for(var _iterator5=file.previewElement.querySelectorAll("[data-dz-remove]"),_isArray5=true,_i5=0,_iterator5=_isArray5?_iterator5:_iterator5[Symbol.iterator]();;){var _ref4;if(_isArray5){if(_i5>=_iterator5.length)break;_ref4=_iterator5[_i5++];}else{_i5=_iterator5.next();if(_i5.done)break;_ref4=_i5.value;} +var removeLink=_ref4;removeLink.addEventListener("click",removeFileEvent);}}},removedfile:function removedfile(file){if(file.previewElement!=null&&file.previewElement.parentNode!=null){file.previewElement.parentNode.removeChild(file.previewElement);} +return this._updateMaxFilesReachedClass();},thumbnail:function thumbnail(file,dataUrl){if(file.previewElement){file.previewElement.classList.remove("dz-file-preview");for(var _iterator6=file.previewElement.querySelectorAll("[data-dz-thumbnail]"),_isArray6=true,_i6=0,_iterator6=_isArray6?_iterator6:_iterator6[Symbol.iterator]();;){var _ref5;if(_isArray6){if(_i6>=_iterator6.length)break;_ref5=_iterator6[_i6++];}else{_i6=_iterator6.next();if(_i6.done)break;_ref5=_i6.value;} +var thumbnailElement=_ref5;thumbnailElement.alt=file.name;thumbnailElement.src=dataUrl;} +return setTimeout(function(){return file.previewElement.classList.add("dz-image-preview");},1);}},error:function error(file,message){if(file.previewElement){file.previewElement.classList.add("dz-error");if(typeof message!=="String"&&message.error){message=message.error;} +for(var _iterator7=file.previewElement.querySelectorAll("[data-dz-errormessage]"),_isArray7=true,_i7=0,_iterator7=_isArray7?_iterator7:_iterator7[Symbol.iterator]();;){var _ref6;if(_isArray7){if(_i7>=_iterator7.length)break;_ref6=_iterator7[_i7++];}else{_i7=_iterator7.next();if(_i7.done)break;_ref6=_i7.value;} +var node=_ref6;node.textContent=message;}}},errormultiple:function errormultiple(){},processing:function processing(file){if(file.previewElement){file.previewElement.classList.add("dz-processing");if(file._removeLink){return file._removeLink.innerHTML=this.options.dictCancelUpload;}}},processingmultiple:function processingmultiple(){},uploadprogress:function uploadprogress(file,progress,bytesSent){if(file.previewElement){for(var _iterator8=file.previewElement.querySelectorAll("[data-dz-uploadprogress]"),_isArray8=true,_i8=0,_iterator8=_isArray8?_iterator8:_iterator8[Symbol.iterator]();;){var _ref7;if(_isArray8){if(_i8>=_iterator8.length)break;_ref7=_iterator8[_i8++];}else{_i8=_iterator8.next();if(_i8.done)break;_ref7=_i8.value;} +var node=_ref7;node.nodeName==='PROGRESS'?node.value=progress:node.style.width=progress+"%";}}},totaluploadprogress:function totaluploadprogress(){},sending:function sending(){},sendingmultiple:function sendingmultiple(){},success:function success(file){if(file.previewElement){return file.previewElement.classList.add("dz-success");}},successmultiple:function successmultiple(){},canceled:function canceled(file){return this.emit("error",file,this.options.dictUploadCanceled);},canceledmultiple:function canceledmultiple(){},complete:function complete(file){if(file._removeLink){file._removeLink.innerHTML=this.options.dictRemoveFile;} +if(file.previewElement){return file.previewElement.classList.add("dz-complete");}},completemultiple:function completemultiple(){},maxfilesexceeded:function maxfilesexceeded(){},maxfilesreached:function maxfilesreached(){},queuecomplete:function queuecomplete(){},addedfiles:function addedfiles(){}};this.prototype._thumbnailQueue=[];this.prototype._processingThumbnail=false;}},{key:"extend",value:function extend(target){for(var _len2=arguments.length,objects=Array(_len2>1?_len2-1:0),_key2=1;_key2<_len2;_key2++){objects[_key2-1]=arguments[_key2];} +for(var _iterator9=objects,_isArray9=true,_i9=0,_iterator9=_isArray9?_iterator9:_iterator9[Symbol.iterator]();;){var _ref8;if(_isArray9){if(_i9>=_iterator9.length)break;_ref8=_iterator9[_i9++];}else{_i9=_iterator9.next();if(_i9.done)break;_ref8=_i9.value;} +var object=_ref8;for(var key in object){var val=object[key];target[key]=val;}} +return target;}}]);function Dropzone(el,options){_classCallCheck(this,Dropzone);var _this=_possibleConstructorReturn(this,(Dropzone.__proto__||Object.getPrototypeOf(Dropzone)).call(this));var fallback=void 0,left=void 0;_this.element=el;_this.version=Dropzone.version;_this.defaultOptions.previewTemplate=_this.defaultOptions.previewTemplate.replace(/\n*/g,"");_this.clickableElements=[];_this.listeners=[];_this.files=[];if(typeof _this.element==="string"){_this.element=document.querySelector(_this.element);} +if(!_this.element||_this.element.nodeType==null){throw new Error("Invalid dropzone element.");} +if(_this.element.dropzone){throw new Error("Dropzone already attached.");} +Dropzone.instances.push(_this);_this.element.dropzone=_this;var elementOptions=(left=Dropzone.optionsForElement(_this.element))!=null?left:{};_this.options=Dropzone.extend({},_this.defaultOptions,elementOptions,options!=null?options:{});if(_this.options.forceFallback||!Dropzone.isBrowserSupported()){var _ret;return _ret=_this.options.fallback.call(_this),_possibleConstructorReturn(_this,_ret);} +if(_this.options.url==null){_this.options.url=_this.element.getAttribute("action");} +if(!_this.options.url){throw new Error("No URL provided.");} +if(_this.options.acceptedFiles&&_this.options.acceptedMimeTypes){throw new Error("You can't provide both 'acceptedFiles' and 'acceptedMimeTypes'. 'acceptedMimeTypes' is deprecated.");} +if(_this.options.uploadMultiple&&_this.options.chunking){throw new Error('You cannot set both: uploadMultiple and chunking.');} +if(_this.options.acceptedMimeTypes){_this.options.acceptedFiles=_this.options.acceptedMimeTypes;delete _this.options.acceptedMimeTypes;} +if(_this.options.renameFilename!=null){_this.options.renameFile=function(file){return _this.options.renameFilename.call(_this,file.name,file);};} +_this.options.method=_this.options.method.toUpperCase();if((fallback=_this.getExistingFallback())&&fallback.parentNode){fallback.parentNode.removeChild(fallback);} +if(_this.options.previewsContainer!==false){if(_this.options.previewsContainer){_this.previewsContainer=Dropzone.getElement(_this.options.previewsContainer,"previewsContainer");}else{_this.previewsContainer=_this.element;}} +if(_this.options.clickable){if(_this.options.clickable===true){_this.clickableElements=[_this.element];}else{_this.clickableElements=Dropzone.getElements(_this.options.clickable,"clickable");}} +_this.init();return _this;} +_createClass(Dropzone,[{key:"getAcceptedFiles",value:function getAcceptedFiles(){return this.files.filter(function(file){return file.accepted;}).map(function(file){return file;});}},{key:"getRejectedFiles",value:function getRejectedFiles(){return this.files.filter(function(file){return!file.accepted;}).map(function(file){return file;});}},{key:"getFilesWithStatus",value:function getFilesWithStatus(status){return this.files.filter(function(file){return file.status===status;}).map(function(file){return file;});}},{key:"getQueuedFiles",value:function getQueuedFiles(){return this.getFilesWithStatus(Dropzone.QUEUED);}},{key:"getUploadingFiles",value:function getUploadingFiles(){return this.getFilesWithStatus(Dropzone.UPLOADING);}},{key:"getAddedFiles",value:function getAddedFiles(){return this.getFilesWithStatus(Dropzone.ADDED);}},{key:"getActiveFiles",value:function getActiveFiles(){return this.files.filter(function(file){return file.status===Dropzone.UPLOADING||file.status===Dropzone.QUEUED;}).map(function(file){return file;});}},{key:"init",value:function init(){var _this3=this;if(this.element.tagName==="form"){this.element.setAttribute("enctype","multipart/form-data");} if(this.element.classList.contains("dropzone")&&!this.element.querySelector(".dz-message")){this.element.appendChild(Dropzone.createElement("
"+this.options.dictDefaultMessage+"
"));} -if(this.clickableElements.length){setupHiddenFileInput=(function(_this){return function(){if(_this.hiddenFileInput){document.body.removeChild(_this.hiddenFileInput);} -_this.hiddenFileInput=document.createElement("input");_this.hiddenFileInput.setAttribute("type","file");if((_this.options.maxFiles==null)||_this.options.maxFiles>1){_this.hiddenFileInput.setAttribute("multiple","multiple");} -_this.hiddenFileInput.className="dz-hidden-input";if(_this.options.acceptedFiles!=null){_this.hiddenFileInput.setAttribute("accept",_this.options.acceptedFiles);} -if(_this.options.capture!=null){_this.hiddenFileInput.setAttribute("capture",_this.options.capture);} -_this.hiddenFileInput.style.visibility="hidden";_this.hiddenFileInput.style.position="absolute";_this.hiddenFileInput.style.top="0";_this.hiddenFileInput.style.left="0";_this.hiddenFileInput.style.height="0";_this.hiddenFileInput.style.width="0";document.body.appendChild(_this.hiddenFileInput);return _this.hiddenFileInput.addEventListener("change",function(){var file,files,_i,_len;files=_this.hiddenFileInput.files;if(files.length){for(_i=0,_len=files.length;_i<_len;_i++){file=files[_i];_this.addFile(file);}} -return setupHiddenFileInput();});};})(this);setupHiddenFileInput();} -this.URL=(_ref=window.URL)!=null?_ref:window.webkitURL;_ref1=this.events;for(_i=0,_len=_ref1.length;_i<_len;_i++){eventName=_ref1[_i];this.on(eventName,this.options[eventName]);} -this.on("uploadprogress",(function(_this){return function(){return _this.updateTotalUploadProgress();};})(this));this.on("removedfile",(function(_this){return function(){return _this.updateTotalUploadProgress();};})(this));this.on("canceled",(function(_this){return function(file){return _this.emit("complete",file);};})(this));this.on("complete",(function(_this){return function(file){if(_this.getUploadingFiles().length===0&&_this.getQueuedFiles().length===0){return setTimeout((function(){return _this.emit("queuecomplete");}),0);}};})(this));noPropagation=function(e){e.stopPropagation();if(e.preventDefault){return e.preventDefault();}else{return e.returnValue=false;}};this.listeners=[{element:this.element,events:{"dragstart":(function(_this){return function(e){return _this.emit("dragstart",e);};})(this),"dragenter":(function(_this){return function(e){noPropagation(e);return _this.emit("dragenter",e);};})(this),"dragover":(function(_this){return function(e){var efct;try{efct=e.dataTransfer.effectAllowed;}catch(_error){} -e.dataTransfer.dropEffect='move'===efct||'linkMove'===efct?'move':'copy';noPropagation(e);return _this.emit("dragover",e);};})(this),"dragleave":(function(_this){return function(e){return _this.emit("dragleave",e);};})(this),"drop":(function(_this){return function(e){noPropagation(e);return _this.drop(e);};})(this),"dragend":(function(_this){return function(e){return _this.emit("dragend",e);};})(this)}}];this.clickableElements.forEach((function(_this){return function(clickableElement){return _this.listeners.push({element:clickableElement,events:{"click":function(evt){if((clickableElement!==_this.element)||(evt.target===_this.element||Dropzone.elementInside(evt.target,_this.element.querySelector(".dz-message")))){return _this.hiddenFileInput.click();}}}});};})(this));this.enable();return this.options.init.call(this);};Dropzone.prototype.destroy=function(){var _ref;this.disable();this.removeAllFiles(true);if((_ref=this.hiddenFileInput)!=null?_ref.parentNode:void 0){this.hiddenFileInput.parentNode.removeChild(this.hiddenFileInput);this.hiddenFileInput=null;} -delete this.element.dropzone;return Dropzone.instances.splice(Dropzone.instances.indexOf(this),1);};Dropzone.prototype.updateTotalUploadProgress=function(){var activeFiles,file,totalBytes,totalBytesSent,totalUploadProgress,_i,_len,_ref;totalBytesSent=0;totalBytes=0;activeFiles=this.getActiveFiles();if(activeFiles.length){_ref=this.getActiveFiles();for(_i=0,_len=_ref.length;_i<_len;_i++){file=_ref[_i];totalBytesSent+=file.upload.bytesSent;totalBytes+=file.upload.total;} +if(this.clickableElements.length){var setupHiddenFileInput=function setupHiddenFileInput(){if(_this3.hiddenFileInput){_this3.hiddenFileInput.parentNode.removeChild(_this3.hiddenFileInput);} +_this3.hiddenFileInput=document.createElement("input");_this3.hiddenFileInput.setAttribute("type","file");if(_this3.options.maxFiles===null||_this3.options.maxFiles>1){_this3.hiddenFileInput.setAttribute("multiple","multiple");} +_this3.hiddenFileInput.className="dz-hidden-input";if(_this3.options.acceptedFiles!==null){_this3.hiddenFileInput.setAttribute("accept",_this3.options.acceptedFiles);} +if(_this3.options.capture!==null){_this3.hiddenFileInput.setAttribute("capture",_this3.options.capture);} +_this3.hiddenFileInput.style.visibility="hidden";_this3.hiddenFileInput.style.position="absolute";_this3.hiddenFileInput.style.top="0";_this3.hiddenFileInput.style.left="0";_this3.hiddenFileInput.style.height="0";_this3.hiddenFileInput.style.width="0";Dropzone.getElement(_this3.options.hiddenInputContainer,'hiddenInputContainer').appendChild(_this3.hiddenFileInput);return _this3.hiddenFileInput.addEventListener("change",function(){var files=_this3.hiddenFileInput.files;if(files.length){for(var _iterator10=files,_isArray10=true,_i10=0,_iterator10=_isArray10?_iterator10:_iterator10[Symbol.iterator]();;){var _ref9;if(_isArray10){if(_i10>=_iterator10.length)break;_ref9=_iterator10[_i10++];}else{_i10=_iterator10.next();if(_i10.done)break;_ref9=_i10.value;} +var file=_ref9;_this3.addFile(file);}} +_this3.emit("addedfiles",files);return setupHiddenFileInput();});};setupHiddenFileInput();} +this.URL=window.URL!==null?window.URL:window.webkitURL;for(var _iterator11=this.events,_isArray11=true,_i11=0,_iterator11=_isArray11?_iterator11:_iterator11[Symbol.iterator]();;){var _ref10;if(_isArray11){if(_i11>=_iterator11.length)break;_ref10=_iterator11[_i11++];}else{_i11=_iterator11.next();if(_i11.done)break;_ref10=_i11.value;} +var eventName=_ref10;this.on(eventName,this.options[eventName]);} +this.on("uploadprogress",function(){return _this3.updateTotalUploadProgress();});this.on("removedfile",function(){return _this3.updateTotalUploadProgress();});this.on("canceled",function(file){return _this3.emit("complete",file);});this.on("complete",function(file){if(_this3.getAddedFiles().length===0&&_this3.getUploadingFiles().length===0&&_this3.getQueuedFiles().length===0){return setTimeout(function(){return _this3.emit("queuecomplete");},0);}});var noPropagation=function noPropagation(e){e.stopPropagation();if(e.preventDefault){return e.preventDefault();}else{return e.returnValue=false;}};this.listeners=[{element:this.element,events:{"dragstart":function dragstart(e){return _this3.emit("dragstart",e);},"dragenter":function dragenter(e){noPropagation(e);return _this3.emit("dragenter",e);},"dragover":function dragover(e){var efct=void 0;try{efct=e.dataTransfer.effectAllowed;}catch(error){} +e.dataTransfer.dropEffect='move'===efct||'linkMove'===efct?'move':'copy';noPropagation(e);return _this3.emit("dragover",e);},"dragleave":function dragleave(e){return _this3.emit("dragleave",e);},"drop":function drop(e){noPropagation(e);return _this3.drop(e);},"dragend":function dragend(e){return _this3.emit("dragend",e);}}}];this.clickableElements.forEach(function(clickableElement){return _this3.listeners.push({element:clickableElement,events:{"click":function click(evt){if(clickableElement!==_this3.element||evt.target===_this3.element||Dropzone.elementInside(evt.target,_this3.element.querySelector(".dz-message"))){_this3.hiddenFileInput.click();} +return true;}}});});this.enable();return this.options.init.call(this);}},{key:"destroy",value:function destroy(){this.disable();this.removeAllFiles(true);if(this.hiddenFileInput!=null?this.hiddenFileInput.parentNode:undefined){this.hiddenFileInput.parentNode.removeChild(this.hiddenFileInput);this.hiddenFileInput=null;} +delete this.element.dropzone;return Dropzone.instances.splice(Dropzone.instances.indexOf(this),1);}},{key:"updateTotalUploadProgress",value:function updateTotalUploadProgress(){var totalUploadProgress=void 0;var totalBytesSent=0;var totalBytes=0;var activeFiles=this.getActiveFiles();if(activeFiles.length){for(var _iterator12=this.getActiveFiles(),_isArray12=true,_i12=0,_iterator12=_isArray12?_iterator12:_iterator12[Symbol.iterator]();;){var _ref11;if(_isArray12){if(_i12>=_iterator12.length)break;_ref11=_iterator12[_i12++];}else{_i12=_iterator12.next();if(_i12.done)break;_ref11=_i12.value;} +var file=_ref11;totalBytesSent+=file.upload.bytesSent;totalBytes+=file.upload.total;} totalUploadProgress=100*totalBytesSent/totalBytes;}else{totalUploadProgress=100;} -return this.emit("totaluploadprogress",totalUploadProgress,totalBytes,totalBytesSent);};Dropzone.prototype._getParamName=function(n){if(typeof this.options.paramName==="function"){return this.options.paramName(n);}else{return""+this.options.paramName+(this.options.uploadMultiple?"["+n+"]":"");}};Dropzone.prototype.getFallbackForm=function(){var existingFallback,fields,fieldsString,form;if(existingFallback=this.getExistingFallback()){return existingFallback;} -fieldsString="
";if(this.options.dictFallbackText){fieldsString+="

"+this.options.dictFallbackText+"

";} -fieldsString+="
";fields=Dropzone.createElement(fieldsString);if(this.element.tagName!=="FORM"){form=Dropzone.createElement("
");form.appendChild(fields);}else{this.element.setAttribute("enctype","multipart/form-data");this.element.setAttribute("method",this.options.method);} -return form!=null?form:fields;};Dropzone.prototype.getExistingFallback=function(){var fallback,getFallback,tagName,_i,_len,_ref;getFallback=function(elements){var el,_i,_len;for(_i=0,_len=elements.length;_i<_len;_i++){el=elements[_i];if(/(^| )fallback($| )/.test(el.className)){return el;}}};_ref=["div","form"];for(_i=0,_len=_ref.length;_i<_len;_i++){tagName=_ref[_i];if(fallback=getFallback(this.element.getElementsByTagName(tagName))){return fallback;}}};Dropzone.prototype.setupEventListeners=function(){var elementListeners,event,listener,_i,_len,_ref,_results;_ref=this.listeners;_results=[];for(_i=0,_len=_ref.length;_i<_len;_i++){elementListeners=_ref[_i];_results.push((function(){var _ref1,_results1;_ref1=elementListeners.events;_results1=[];for(event in _ref1){listener=_ref1[event];_results1.push(elementListeners.element.addEventListener(event,listener,false));} -return _results1;})());} -return _results;};Dropzone.prototype.removeEventListeners=function(){var elementListeners,event,listener,_i,_len,_ref,_results;_ref=this.listeners;_results=[];for(_i=0,_len=_ref.length;_i<_len;_i++){elementListeners=_ref[_i];_results.push((function(){var _ref1,_results1;_ref1=elementListeners.events;_results1=[];for(event in _ref1){listener=_ref1[event];_results1.push(elementListeners.element.removeEventListener(event,listener,false));} -return _results1;})());} -return _results;};Dropzone.prototype.disable=function(){var file,_i,_len,_ref,_results;this.clickableElements.forEach(function(element){return element.classList.remove("dz-clickable");});this.removeEventListeners();_ref=this.files;_results=[];for(_i=0,_len=_ref.length;_i<_len;_i++){file=_ref[_i];_results.push(this.cancelUpload(file));} -return _results;};Dropzone.prototype.enable=function(){this.clickableElements.forEach(function(element){return element.classList.add("dz-clickable");});return this.setupEventListeners();};Dropzone.prototype.filesize=function(size){var cutoff,i,selectedSize,selectedUnit,unit,units,_i,_len;units=['TB','GB','MB','KB','b'];selectedSize=selectedUnit=null;for(i=_i=0,_len=units.length;_i<_len;i=++_i){unit=units[i];cutoff=Math.pow(this.options.filesizeBase,4-i)/10;if(size>=cutoff){selectedSize=size/Math.pow(this.options.filesizeBase,4-i);selectedUnit=unit;break;}} -selectedSize=Math.round(10*selectedSize)/10;return""+selectedSize+" "+selectedUnit;};Dropzone.prototype._updateMaxFilesReachedClass=function(){if((this.options.maxFiles!=null)&&this.getAcceptedFiles().length>=this.options.maxFiles){if(this.getAcceptedFiles().length===this.options.maxFiles){this.emit('maxfilesreached',this.files);} -return this.element.classList.add("dz-max-files-reached");}else{return this.element.classList.remove("dz-max-files-reached");}};Dropzone.prototype.drop=function(e){var files,items;if(!e.dataTransfer){return;} -this.emit("drop",e);files=e.dataTransfer.files;if(files.length){items=e.dataTransfer.items;if(items&&items.length&&(items[0].webkitGetAsEntry!=null)){this._addFilesFromItems(items);}else{this.handleFiles(files);}}};Dropzone.prototype.paste=function(e){var items,_ref;if((e!=null?(_ref=e.clipboardData)!=null?_ref.items:void 0:void 0)==null){return;} -this.emit("paste",e);items=e.clipboardData.items;if(items.length){return this._addFilesFromItems(items);}};Dropzone.prototype.handleFiles=function(files){var file,_i,_len,_results;_results=[];for(_i=0,_len=files.length;_i<_len;_i++){file=files[_i];_results.push(this.addFile(file));} -return _results;};Dropzone.prototype._addFilesFromItems=function(items){var entry,item,_i,_len,_results;_results=[];for(_i=0,_len=items.length;_i<_len;_i++){item=items[_i];if((item.webkitGetAsEntry!=null)&&(entry=item.webkitGetAsEntry())){if(entry.isFile){_results.push(this.addFile(item.getAsFile()));}else if(entry.isDirectory){_results.push(this._addFilesFromDirectory(entry,entry.name));}else{_results.push(void 0);}}else if(item.getAsFile!=null){if((item.kind==null)||item.kind==="file"){_results.push(this.addFile(item.getAsFile()));}else{_results.push(void 0);}}else{_results.push(void 0);}} -return _results;};Dropzone.prototype._addFilesFromDirectory=function(directory,path){var dirReader,entriesReader;dirReader=directory.createReader();entriesReader=(function(_this){return function(entries){var entry,_i,_len;for(_i=0,_len=entries.length;_i<_len;_i++){entry=entries[_i];if(entry.isFile){entry.file(function(file){if(_this.options.ignoreHiddenFiles&&file.name.substring(0,1)==='.'){return;} -file.fullPath=""+path+"/"+file.name;return _this.addFile(file);});}else if(entry.isDirectory){_this._addFilesFromDirectory(entry,""+path+"/"+entry.name);}}};})(this);return dirReader.readEntries(entriesReader,function(error){return typeof console!=="undefined"&&console!==null?typeof console.log==="function"?console.log(error):void 0:void 0;});};Dropzone.prototype.accept=function(file,done){if(file.size>this.options.maxFilesize*1024*1024){return done(this.options.dictFileTooBig.replace("{{filesize}}",Math.round(file.size/1024/10.24)/100).replace("{{maxFilesize}}",this.options.maxFilesize));}else if(!Dropzone.isValidFile(file,this.options.acceptedFiles)){return done(this.options.dictInvalidFileType);}else if((this.options.maxFiles!=null)&&this.getAcceptedFiles().length>=this.options.maxFiles){done(this.options.dictMaxFilesExceeded.replace("{{maxFiles}}",this.options.maxFiles));return this.emit("maxfilesexceeded",file);}else{return this.options.accept.call(this,file,done);}};Dropzone.prototype.addFile=function(file){file.upload={progress:0,total:file.size,bytesSent:0};this.files.push(file);file.status=Dropzone.ADDED;this.emit("addedfile",file);this._enqueueThumbnail(file);return this.accept(file,(function(_this){return function(error){if(error){file.accepted=false;_this._errorProcessing([file],error);}else{file.accepted=true;if(_this.options.autoQueue){_this.enqueueFile(file);}} -return _this._updateMaxFilesReachedClass();};})(this));};Dropzone.prototype.enqueueFiles=function(files){var file,_i,_len;for(_i=0,_len=files.length;_i<_len;_i++){file=files[_i];this.enqueueFile(file);} -return null;};Dropzone.prototype.enqueueFile=function(file){if(file.status===Dropzone.ADDED&&file.accepted===true){file.status=Dropzone.QUEUED;if(this.options.autoProcessQueue){return setTimeout(((function(_this){return function(){return _this.processQueue();};})(this)),0);}}else{throw new Error("This file can't be queued because it has already been processed or was rejected.");}};Dropzone.prototype._thumbnailQueue=[];Dropzone.prototype._processingThumbnail=false;Dropzone.prototype._enqueueThumbnail=function(file){if(this.options.createImageThumbnails&&file.type.match(/image.*/)&&file.size<=this.options.maxThumbnailFilesize*1024*1024){this._thumbnailQueue.push(file);return setTimeout(((function(_this){return function(){return _this._processThumbnailQueue();};})(this)),0);}};Dropzone.prototype._processThumbnailQueue=function(){if(this._processingThumbnail||this._thumbnailQueue.length===0){return;} -this._processingThumbnail=true;return this.createThumbnail(this._thumbnailQueue.shift(),(function(_this){return function(){_this._processingThumbnail=false;return _this._processThumbnailQueue();};})(this));};Dropzone.prototype.removeFile=function(file){if(file.status===Dropzone.UPLOADING){this.cancelUpload(file);} -this.files=without(this.files,file);this.emit("removedfile",file);if(this.files.length===0){return this.emit("reset");}};Dropzone.prototype.removeAllFiles=function(cancelIfNecessary){var file,_i,_len,_ref;if(cancelIfNecessary==null){cancelIfNecessary=false;} -_ref=this.files.slice();for(_i=0,_len=_ref.length;_i<_len;_i++){file=_ref[_i];if(file.status!==Dropzone.UPLOADING||cancelIfNecessary){this.removeFile(file);}} -return null;};Dropzone.prototype.createThumbnail=function(file,callback){var fileReader;fileReader=new FileReader;fileReader.onload=(function(_this){return function(){if(file.type==="image/svg+xml"){_this.emit("thumbnail",file,fileReader.result);if(callback!=null){callback();} +return this.emit("totaluploadprogress",totalUploadProgress,totalBytes,totalBytesSent);}},{key:"_getParamName",value:function _getParamName(n){if(typeof this.options.paramName==="function"){return this.options.paramName(n);}else{return""+this.options.paramName+(this.options.uploadMultiple?"["+n+"]":"");}}},{key:"_renameFile",value:function _renameFile(file){if(typeof this.options.renameFile!=="function"){return file.name;} +return this.options.renameFile(file);}},{key:"getFallbackForm",value:function getFallbackForm(){var existingFallback=void 0,form=void 0;if(existingFallback=this.getExistingFallback()){return existingFallback;} +var fieldsString="
";if(this.options.dictFallbackText){fieldsString+="

"+this.options.dictFallbackText+"

";} +fieldsString+="
";var fields=Dropzone.createElement(fieldsString);if(this.element.tagName!=="FORM"){form=Dropzone.createElement("
");form.appendChild(fields);}else{this.element.setAttribute("enctype","multipart/form-data");this.element.setAttribute("method",this.options.method);} +return form!=null?form:fields;}},{key:"getExistingFallback",value:function getExistingFallback(){var getFallback=function getFallback(elements){for(var _iterator13=elements,_isArray13=true,_i13=0,_iterator13=_isArray13?_iterator13:_iterator13[Symbol.iterator]();;){var _ref12;if(_isArray13){if(_i13>=_iterator13.length)break;_ref12=_iterator13[_i13++];}else{_i13=_iterator13.next();if(_i13.done)break;_ref12=_i13.value;} +var el=_ref12;if(/(^| )fallback($| )/.test(el.className)){return el;}}};var _arr=["div","form"];for(var _i14=0;_i14<_arr.length;_i14++){var tagName=_arr[_i14];var fallback;if(fallback=getFallback(this.element.getElementsByTagName(tagName))){return fallback;}}}},{key:"setupEventListeners",value:function setupEventListeners(){return this.listeners.map(function(elementListeners){return function(){var result=[];for(var event in elementListeners.events){var listener=elementListeners.events[event];result.push(elementListeners.element.addEventListener(event,listener,false));} +return result;}();});}},{key:"removeEventListeners",value:function removeEventListeners(){return this.listeners.map(function(elementListeners){return function(){var result=[];for(var event in elementListeners.events){var listener=elementListeners.events[event];result.push(elementListeners.element.removeEventListener(event,listener,false));} +return result;}();});}},{key:"disable",value:function disable(){var _this4=this;this.clickableElements.forEach(function(element){return element.classList.remove("dz-clickable");});this.removeEventListeners();this.disabled=true;return this.files.map(function(file){return _this4.cancelUpload(file);});}},{key:"enable",value:function enable(){delete this.disabled;this.clickableElements.forEach(function(element){return element.classList.add("dz-clickable");});return this.setupEventListeners();}},{key:"filesize",value:function filesize(size){var selectedSize=0;var selectedUnit="b";if(size>0){var units=['tb','gb','mb','kb','b'];for(var i=0;i=cutoff){selectedSize=size/Math.pow(this.options.filesizeBase,4-i);selectedUnit=unit;break;}} +selectedSize=Math.round(10*selectedSize)/10;} +return""+selectedSize+" "+this.options.dictFileSizeUnits[selectedUnit];}},{key:"_updateMaxFilesReachedClass",value:function _updateMaxFilesReachedClass(){if(this.options.maxFiles!=null&&this.getAcceptedFiles().length>=this.options.maxFiles){if(this.getAcceptedFiles().length===this.options.maxFiles){this.emit('maxfilesreached',this.files);} +return this.element.classList.add("dz-max-files-reached");}else{return this.element.classList.remove("dz-max-files-reached");}}},{key:"drop",value:function drop(e){if(!e.dataTransfer){return;} +this.emit("drop",e);var files=[];for(var i=0;i=_iterator14.length)break;_ref13=_iterator14[_i15++];}else{_i15=_iterator14.next();if(_i15.done)break;_ref13=_i15.value;} +var file=_ref13;this.addFile(file);}}},{key:"_addFilesFromItems",value:function _addFilesFromItems(items){var _this5=this;return function(){var result=[];for(var _iterator15=items,_isArray15=true,_i16=0,_iterator15=_isArray15?_iterator15:_iterator15[Symbol.iterator]();;){var _ref14;if(_isArray15){if(_i16>=_iterator15.length)break;_ref14=_iterator15[_i16++];}else{_i16=_iterator15.next();if(_i16.done)break;_ref14=_i16.value;} +var item=_ref14;var entry;if(item.webkitGetAsEntry!=null&&(entry=item.webkitGetAsEntry())){if(entry.isFile){result.push(_this5.addFile(item.getAsFile()));}else if(entry.isDirectory){result.push(_this5._addFilesFromDirectory(entry,entry.name));}else{result.push(undefined);}}else if(item.getAsFile!=null){if(item.kind==null||item.kind==="file"){result.push(_this5.addFile(item.getAsFile()));}else{result.push(undefined);}}else{result.push(undefined);}} +return result;}();}},{key:"_addFilesFromDirectory",value:function _addFilesFromDirectory(directory,path){var _this6=this;var dirReader=directory.createReader();var errorHandler=function errorHandler(error){return __guardMethod__(console,'log',function(o){return o.log(error);});};var readEntries=function readEntries(){return dirReader.readEntries(function(entries){if(entries.length>0){for(var _iterator16=entries,_isArray16=true,_i17=0,_iterator16=_isArray16?_iterator16:_iterator16[Symbol.iterator]();;){var _ref15;if(_isArray16){if(_i17>=_iterator16.length)break;_ref15=_iterator16[_i17++];}else{_i17=_iterator16.next();if(_i17.done)break;_ref15=_i17.value;} +var entry=_ref15;if(entry.isFile){entry.file(function(file){if(_this6.options.ignoreHiddenFiles&&file.name.substring(0,1)==='.'){return;} +file.fullPath=path+"/"+file.name;return _this6.addFile(file);});}else if(entry.isDirectory){_this6._addFilesFromDirectory(entry,path+"/"+entry.name);}} +readEntries();} +return null;},errorHandler);};return readEntries();}},{key:"accept",value:function accept(file,done){if(this.options.maxFilesize&&file.size>this.options.maxFilesize*1024*1024){return done(this.options.dictFileTooBig.replace("{{filesize}}",Math.round(file.size/1024/10.24)/100).replace("{{maxFilesize}}",this.options.maxFilesize));}else if(!Dropzone.isValidFile(file,this.options.acceptedFiles)){return done(this.options.dictInvalidFileType);}else if(this.options.maxFiles!=null&&this.getAcceptedFiles().length>=this.options.maxFiles){done(this.options.dictMaxFilesExceeded.replace("{{maxFiles}}",this.options.maxFiles));return this.emit("maxfilesexceeded",file);}else{return this.options.accept.call(this,file,done);}}},{key:"addFile",value:function addFile(file){var _this7=this;file.upload={uuid:Dropzone.uuidv4(),progress:0,total:file.size,bytesSent:0,filename:this._renameFile(file),chunked:this.options.chunking&&(this.options.forceChunking||file.size>this.options.chunkSize),totalChunkCount:Math.ceil(file.size/this.options.chunkSize)};this.files.push(file);file.status=Dropzone.ADDED;this.emit("addedfile",file);this._enqueueThumbnail(file);return this.accept(file,function(error){if(error){file.accepted=false;_this7._errorProcessing([file],error);}else{file.accepted=true;if(_this7.options.autoQueue){_this7.enqueueFile(file);}} +return _this7._updateMaxFilesReachedClass();});}},{key:"enqueueFiles",value:function enqueueFiles(files){for(var _iterator17=files,_isArray17=true,_i18=0,_iterator17=_isArray17?_iterator17:_iterator17[Symbol.iterator]();;){var _ref16;if(_isArray17){if(_i18>=_iterator17.length)break;_ref16=_iterator17[_i18++];}else{_i18=_iterator17.next();if(_i18.done)break;_ref16=_i18.value;} +var file=_ref16;this.enqueueFile(file);} +return null;}},{key:"enqueueFile",value:function enqueueFile(file){var _this8=this;if(file.status===Dropzone.ADDED&&file.accepted===true){file.status=Dropzone.QUEUED;if(this.options.autoProcessQueue){return setTimeout(function(){return _this8.processQueue();},0);}}else{throw new Error("This file can't be queued because it has already been processed or was rejected.");}}},{key:"_enqueueThumbnail",value:function _enqueueThumbnail(file){var _this9=this;if(this.options.createImageThumbnails&&file.type.match(/image.*/)&&file.size<=this.options.maxThumbnailFilesize*1024*1024){this._thumbnailQueue.push(file);return setTimeout(function(){return _this9._processThumbnailQueue();},0);}}},{key:"_processThumbnailQueue",value:function _processThumbnailQueue(){var _this10=this;if(this._processingThumbnail||this._thumbnailQueue.length===0){return;} +this._processingThumbnail=true;var file=this._thumbnailQueue.shift();return this.createThumbnail(file,this.options.thumbnailWidth,this.options.thumbnailHeight,this.options.thumbnailMethod,true,function(dataUrl){_this10.emit("thumbnail",file,dataUrl);_this10._processingThumbnail=false;return _this10._processThumbnailQueue();});}},{key:"removeFile",value:function removeFile(file){if(file.status===Dropzone.UPLOADING){this.cancelUpload(file);} +this.files=without(this.files,file);this.emit("removedfile",file);if(this.files.length===0){return this.emit("reset");}}},{key:"removeAllFiles",value:function removeAllFiles(cancelIfNecessary){if(cancelIfNecessary==null){cancelIfNecessary=false;} +for(var _iterator18=this.files.slice(),_isArray18=true,_i19=0,_iterator18=_isArray18?_iterator18:_iterator18[Symbol.iterator]();;){var _ref17;if(_isArray18){if(_i19>=_iterator18.length)break;_ref17=_iterator18[_i19++];}else{_i19=_iterator18.next();if(_i19.done)break;_ref17=_i19.value;} +var file=_ref17;if(file.status!==Dropzone.UPLOADING||cancelIfNecessary){this.removeFile(file);}} +return null;}},{key:"resizeImage",value:function resizeImage(file,width,height,resizeMethod,callback){var _this11=this;return this.createThumbnail(file,width,height,resizeMethod,true,function(dataUrl,canvas){if(canvas==null){return callback(file);}else{var resizeMimeType=_this11.options.resizeMimeType;if(resizeMimeType==null){resizeMimeType=file.type;} +var resizedDataURL=canvas.toDataURL(resizeMimeType,_this11.options.resizeQuality);if(resizeMimeType==='image/jpeg'||resizeMimeType==='image/jpg'){resizedDataURL=ExifRestore.restore(file.dataURL,resizedDataURL);} +return callback(Dropzone.dataURItoBlob(resizedDataURL));}});}},{key:"createThumbnail",value:function createThumbnail(file,width,height,resizeMethod,fixOrientation,callback){var _this12=this;var fileReader=new FileReader();fileReader.onload=function(){file.dataURL=fileReader.result;if(file.type==="image/svg+xml"){if(callback!=null){callback(fileReader.result);} return;} -return _this.createThumbnailFromUrl(file,fileReader.result,callback);};})(this);return fileReader.readAsDataURL(file);};Dropzone.prototype.createThumbnailFromUrl=function(file,imageUrl,callback){var img;img=document.createElement("img");img.onload=(function(_this){return function(){var canvas,ctx,resizeInfo,thumbnail,_ref,_ref1,_ref2,_ref3;file.width=img.width;file.height=img.height;resizeInfo=_this.options.resize.call(_this,file);if(resizeInfo.trgWidth==null){resizeInfo.trgWidth=resizeInfo.optWidth;} -if(resizeInfo.trgHeight==null){resizeInfo.trgHeight=resizeInfo.optHeight;} -canvas=document.createElement("canvas");ctx=canvas.getContext("2d");canvas.width=resizeInfo.trgWidth;canvas.height=resizeInfo.trgHeight;drawImageIOSFix(ctx,img,(_ref=resizeInfo.srcX)!=null?_ref:0,(_ref1=resizeInfo.srcY)!=null?_ref1:0,resizeInfo.srcWidth,resizeInfo.srcHeight,(_ref2=resizeInfo.trgX)!=null?_ref2:0,(_ref3=resizeInfo.trgY)!=null?_ref3:0,resizeInfo.trgWidth,resizeInfo.trgHeight);thumbnail=canvas.toDataURL("image/png");_this.emit("thumbnail",file,thumbnail);if(callback!=null){return callback();}};})(this);if(callback!=null){img.onerror=callback;} -return img.src=imageUrl;};Dropzone.prototype.processQueue=function(){var i,parallelUploads,processingLength,queuedFiles;parallelUploads=this.options.parallelUploads;processingLength=this.getUploadingFiles().length;i=processingLength;if(processingLength>=parallelUploads){return;} -queuedFiles=this.getQueuedFiles();if(!(queuedFiles.length>0)){return;} +return _this12.createThumbnailFromUrl(file,width,height,resizeMethod,fixOrientation,callback);};return fileReader.readAsDataURL(file);}},{key:"createThumbnailFromUrl",value:function createThumbnailFromUrl(file,width,height,resizeMethod,fixOrientation,callback,crossOrigin){var _this13=this;var img=document.createElement("img");if(crossOrigin){img.crossOrigin=crossOrigin;} +img.onload=function(){var loadExif=function loadExif(callback){return callback(1);};if(typeof EXIF!=='undefined'&&EXIF!==null&&fixOrientation){loadExif=function loadExif(callback){return EXIF.getData(img,function(){return callback(EXIF.getTag(this,'Orientation'));});};} +return loadExif(function(orientation){file.width=img.width;file.height=img.height;var resizeInfo=_this13.options.resize.call(_this13,file,width,height,resizeMethod);var canvas=document.createElement("canvas");var ctx=canvas.getContext("2d");canvas.width=resizeInfo.trgWidth;canvas.height=resizeInfo.trgHeight;if(orientation>4){canvas.width=resizeInfo.trgHeight;canvas.height=resizeInfo.trgWidth;} +switch(orientation){case 2:ctx.translate(canvas.width,0);ctx.scale(-1,1);break;case 3:ctx.translate(canvas.width,canvas.height);ctx.rotate(Math.PI);break;case 4:ctx.translate(0,canvas.height);ctx.scale(1,-1);break;case 5:ctx.rotate(0.5*Math.PI);ctx.scale(1,-1);break;case 6:ctx.rotate(0.5*Math.PI);ctx.translate(0,-canvas.width);break;case 7:ctx.rotate(0.5*Math.PI);ctx.translate(canvas.height,-canvas.width);ctx.scale(-1,1);break;case 8:ctx.rotate(-0.5*Math.PI);ctx.translate(-canvas.height,0);break;} +drawImageIOSFix(ctx,img,resizeInfo.srcX!=null?resizeInfo.srcX:0,resizeInfo.srcY!=null?resizeInfo.srcY:0,resizeInfo.srcWidth,resizeInfo.srcHeight,resizeInfo.trgX!=null?resizeInfo.trgX:0,resizeInfo.trgY!=null?resizeInfo.trgY:0,resizeInfo.trgWidth,resizeInfo.trgHeight);var thumbnail=canvas.toDataURL("image/png");if(callback!=null){return callback(thumbnail,canvas);}});};if(callback!=null){img.onerror=callback;} +return img.src=file.dataURL;}},{key:"processQueue",value:function processQueue(){var parallelUploads=this.options.parallelUploads;var processingLength=this.getUploadingFiles().length;var i=processingLength;if(processingLength>=parallelUploads){return;} +var queuedFiles=this.getQueuedFiles();if(!(queuedFiles.length>0)){return;} if(this.options.uploadMultiple){return this.processFiles(queuedFiles.slice(0,parallelUploads-processingLength));}else{while(i=_iterator19.length)break;_ref18=_iterator19[_i20++];}else{_i20=_iterator19.next();if(_i20.done)break;_ref18=_i20.value;} +var file=_ref18;file.processing=true;file.status=Dropzone.UPLOADING;this.emit("processing",file);} if(this.options.uploadMultiple){this.emit("processingmultiple",files);} -return this.uploadFiles(files);};Dropzone.prototype._getFilesWithXhr=function(xhr){var file,files;return files=(function(){var _i,_len,_ref,_results;_ref=this.files;_results=[];for(_i=0,_len=_ref.length;_i<_len;_i++){file=_ref[_i];if(file.xhr===xhr){_results.push(file);}} -return _results;}).call(this);};Dropzone.prototype.cancelUpload=function(file){var groupedFile,groupedFiles,_i,_j,_len,_len1,_ref;if(file.status===Dropzone.UPLOADING){groupedFiles=this._getFilesWithXhr(file.xhr);for(_i=0,_len=groupedFiles.length;_i<_len;_i++){groupedFile=groupedFiles[_i];groupedFile.status=Dropzone.CANCELED;} -file.xhr.abort();for(_j=0,_len1=groupedFiles.length;_j<_len1;_j++){groupedFile=groupedFiles[_j];this.emit("canceled",groupedFile);} -if(this.options.uploadMultiple){this.emit("canceledmultiple",groupedFiles);}}else if((_ref=file.status)===Dropzone.ADDED||_ref===Dropzone.QUEUED){file.status=Dropzone.CANCELED;this.emit("canceled",file);if(this.options.uploadMultiple){this.emit("canceledmultiple",[file]);}} -if(this.options.autoProcessQueue){return this.processQueue();}};resolveOption=function(){var args,option;option=arguments[0],args=2<=arguments.length?__slice.call(arguments,1):[];if(typeof option==='function'){return option.apply(this,args);} -return option;};Dropzone.prototype.uploadFile=function(file){return this.uploadFiles([file]);};Dropzone.prototype.uploadFiles=function(files){var file,formData,handleError,headerName,headerValue,headers,i,input,inputName,inputType,key,method,option,progressObj,response,updateProgress,url,value,xhr,_i,_j,_k,_l,_len,_len1,_len2,_len3,_m,_ref,_ref1,_ref2,_ref3,_ref4,_ref5;xhr=new XMLHttpRequest();for(_i=0,_len=files.length;_i<_len;_i++){file=files[_i];file.xhr=xhr;} -method=resolveOption(this.options.method,files);url=resolveOption(this.options.url,files);xhr.open(method,url,true);xhr.withCredentials=!!this.options.withCredentials;response=null;handleError=(function(_this){return function(){var _j,_len1,_results;_results=[];for(_j=0,_len1=files.length;_j<_len1;_j++){file=files[_j];_results.push(_this._errorProcessing(files,response||_this.options.dictResponseError.replace("{{statusCode}}",xhr.status),xhr));} -return _results;};})(this);updateProgress=(function(_this){return function(e){var allFilesFinished,progress,_j,_k,_l,_len1,_len2,_len3,_results;if(e!=null){progress=100*e.loaded/e.total;for(_j=0,_len1=files.length;_j<_len1;_j++){file=files[_j];file.upload={progress:progress,total:e.total,bytesSent:e.loaded};}}else{allFilesFinished=true;progress=100;for(_k=0,_len2=files.length;_k<_len2;_k++){file=files[_k];if(!(file.upload.progress===100&&file.upload.bytesSent===file.upload.total)){allFilesFinished=false;} -file.upload.progress=progress;file.upload.bytesSent=file.upload.total;} -if(allFilesFinished){return;}} -_results=[];for(_l=0,_len3=files.length;_l<_len3;_l++){file=files[_l];_results.push(_this.emit("uploadprogress",file,progress,file.upload.bytesSent));} -return _results;};})(this);xhr.onload=(function(_this){return function(e){var _ref;if(files[0].status===Dropzone.CANCELED){return;} -if(xhr.readyState!==4){return;} -response=xhr.responseText;if(xhr.getResponseHeader("content-type")&&~xhr.getResponseHeader("content-type").indexOf("application/json")){try{response=JSON.parse(response);}catch(_error){e=_error;response="Invalid JSON response from server.";}} -updateProgress();if(!((200<=(_ref=xhr.status)&&_ref<300))){return handleError();}else{return _this._finished(files,response,e);}};})(this);xhr.onerror=(function(_this){return function(){if(files[0].status===Dropzone.CANCELED){return;} -return handleError();};})(this);progressObj=(_ref=xhr.upload)!=null?_ref:xhr;progressObj.onprogress=updateProgress;headers={"Accept":"application/json","Cache-Control":"no-cache","X-Requested-With":"XMLHttpRequest"};if(this.options.headers){extend(headers,this.options.headers);} -for(headerName in headers){headerValue=headers[headerName];xhr.setRequestHeader(headerName,headerValue);} -formData=new FormData();if(this.options.params){_ref1=this.options.params;for(key in _ref1){value=_ref1[key];formData.append(key,value);}} -for(_j=0,_len1=files.length;_j<_len1;_j++){file=files[_j];this.emit("sending",file,xhr,formData);} +return this.uploadFiles(files);}},{key:"_getFilesWithXhr",value:function _getFilesWithXhr(xhr){var files=void 0;return files=this.files.filter(function(file){return file.xhr===xhr;}).map(function(file){return file;});}},{key:"cancelUpload",value:function cancelUpload(file){if(file.status===Dropzone.UPLOADING){var groupedFiles=this._getFilesWithXhr(file.xhr);for(var _iterator20=groupedFiles,_isArray20=true,_i21=0,_iterator20=_isArray20?_iterator20:_iterator20[Symbol.iterator]();;){var _ref19;if(_isArray20){if(_i21>=_iterator20.length)break;_ref19=_iterator20[_i21++];}else{_i21=_iterator20.next();if(_i21.done)break;_ref19=_i21.value;} +var groupedFile=_ref19;groupedFile.status=Dropzone.CANCELED;} +if(typeof file.xhr!=='undefined'){file.xhr.abort();} +for(var _iterator21=groupedFiles,_isArray21=true,_i22=0,_iterator21=_isArray21?_iterator21:_iterator21[Symbol.iterator]();;){var _ref20;if(_isArray21){if(_i22>=_iterator21.length)break;_ref20=_iterator21[_i22++];}else{_i22=_iterator21.next();if(_i22.done)break;_ref20=_i22.value;} +var _groupedFile=_ref20;this.emit("canceled",_groupedFile);} +if(this.options.uploadMultiple){this.emit("canceledmultiple",groupedFiles);}}else if(file.status===Dropzone.ADDED||file.status===Dropzone.QUEUED){file.status=Dropzone.CANCELED;this.emit("canceled",file);if(this.options.uploadMultiple){this.emit("canceledmultiple",[file]);}} +if(this.options.autoProcessQueue){return this.processQueue();}}},{key:"resolveOption",value:function resolveOption(option){if(typeof option==='function'){for(var _len3=arguments.length,args=Array(_len3>1?_len3-1:0),_key3=1;_key3<_len3;_key3++){args[_key3-1]=arguments[_key3];} +return option.apply(this,args);} +return option;}},{key:"uploadFile",value:function uploadFile(file){return this.uploadFiles([file]);}},{key:"uploadFiles",value:function uploadFiles(files){var _this14=this;this._transformFiles(files,function(transformedFiles){if(files[0].upload.chunked){var file=files[0];var transformedFile=transformedFiles[0];var startedChunkCount=0;file.upload.chunks=[];var handleNextChunk=function handleNextChunk(){var chunkIndex=0;while(file.upload.chunks[chunkIndex]!==undefined){chunkIndex++;} +if(chunkIndex>=file.upload.totalChunkCount)return;startedChunkCount++;var start=chunkIndex*_this14.options.chunkSize;var end=Math.min(start+_this14.options.chunkSize,file.size);var dataBlock={name:_this14._getParamName(0),data:transformedFile.webkitSlice?transformedFile.webkitSlice(start,end):transformedFile.slice(start,end),filename:file.upload.filename,chunkIndex:chunkIndex};file.upload.chunks[chunkIndex]={file:file,index:chunkIndex,dataBlock:dataBlock,status:Dropzone.UPLOADING,progress:0,retries:0};_this14._uploadData(files,[dataBlock]);};file.upload.finishedChunkUpload=function(chunk){var allFinished=true;chunk.status=Dropzone.SUCCESS;chunk.dataBlock=null;chunk.xhr=null;for(var i=0;i=_iterator22.length)break;_ref21=_iterator22[_i24++];}else{_i24=_iterator22.next();if(_i24.done)break;_ref21=_i24.value;} +var file=_ref21;file.xhr=xhr;} +if(files[0].upload.chunked){files[0].upload.chunks[dataBlocks[0].chunkIndex].xhr=xhr;} +var method=this.resolveOption(this.options.method,files);var url=this.resolveOption(this.options.url,files);xhr.open(method,url,true);xhr.timeout=this.resolveOption(this.options.timeout,files);xhr.withCredentials=!!this.options.withCredentials;xhr.onload=function(e){_this15._finishedUploading(files,xhr,e);};xhr.onerror=function(){_this15._handleUploadError(files,xhr);};var progressObj=xhr.upload!=null?xhr.upload:xhr;progressObj.onprogress=function(e){return _this15._updateFilesUploadProgress(files,xhr,e);};var headers={"Accept":"application/json","Cache-Control":"no-cache","X-Requested-With":"XMLHttpRequest"};if(this.options.headers){Dropzone.extend(headers,this.options.headers);} +for(var headerName in headers){var headerValue=headers[headerName];if(headerValue){xhr.setRequestHeader(headerName,headerValue);}} +var formData=new FormData();if(this.options.params){var additionalParams=this.options.params;if(typeof additionalParams==='function'){additionalParams=additionalParams.call(this,files,xhr,files[0].upload.chunked?this._getChunk(files[0],xhr):null);} +for(var key in additionalParams){var value=additionalParams[key];formData.append(key,value);}} +for(var _iterator23=files,_isArray23=true,_i25=0,_iterator23=_isArray23?_iterator23:_iterator23[Symbol.iterator]();;){var _ref22;if(_isArray23){if(_i25>=_iterator23.length)break;_ref22=_iterator23[_i25++];}else{_i25=_iterator23.next();if(_i25.done)break;_ref22=_i25.value;} +var _file=_ref22;this.emit("sending",_file,xhr,formData);} if(this.options.uploadMultiple){this.emit("sendingmultiple",files,xhr,formData);} -if(this.element.tagName==="FORM"){_ref2=this.element.querySelectorAll("input, textarea, select, button");for(_k=0,_len2=_ref2.length;_k<_len2;_k++){input=_ref2[_k];inputName=input.getAttribute("name");inputType=input.getAttribute("type");if(input.tagName==="SELECT"&&input.hasAttribute("multiple")){_ref3=input.options;for(_l=0,_len3=_ref3.length;_l<_len3;_l++){option=_ref3[_l];if(option.selected){formData.append(inputName,option.value);}}}else if(!inputType||((_ref4=inputType.toLowerCase())!=="checkbox"&&_ref4!=="radio")||input.checked){formData.append(inputName,input.value);}}} -for(i=_m=0,_ref5=files.length-1;0<=_ref5?_m<=_ref5:_m>=_ref5;i=0<=_ref5?++_m:--_m){formData.append(this._getParamName(i),files[i],files[i].name);} -return xhr.send(formData);};Dropzone.prototype._finished=function(files,responseText,e){var file,_i,_len;for(_i=0,_len=files.length;_i<_len;_i++){file=files[_i];file.status=Dropzone.SUCCESS;this.emit("success",file,responseText,e);this.emit("complete",file);} +this._addFormElementData(formData);for(var i=0;i=_iterator24.length)break;_ref23=_iterator24[_i26++];}else{_i26=_iterator24.next();if(_i26.done)break;_ref23=_i26.value;} +var input=_ref23;var inputName=input.getAttribute("name");var inputType=input.getAttribute("type");if(inputType)inputType=inputType.toLowerCase();if(typeof inputName==='undefined'||inputName===null)continue;if(input.tagName==="SELECT"&&input.hasAttribute("multiple")){for(var _iterator25=input.options,_isArray25=true,_i27=0,_iterator25=_isArray25?_iterator25:_iterator25[Symbol.iterator]();;){var _ref24;if(_isArray25){if(_i27>=_iterator25.length)break;_ref24=_iterator25[_i27++];}else{_i27=_iterator25.next();if(_i27.done)break;_ref24=_i27.value;} +var option=_ref24;if(option.selected){formData.append(inputName,option.value);}}}else if(!inputType||inputType!=="checkbox"&&inputType!=="radio"||input.checked){formData.append(inputName,input.value);}}}}},{key:"_updateFilesUploadProgress",value:function _updateFilesUploadProgress(files,xhr,e){var progress=void 0;if(typeof e!=='undefined'){progress=100*e.loaded/e.total;if(files[0].upload.chunked){var file=files[0];var chunk=this._getChunk(file,xhr);chunk.progress=progress;chunk.total=e.total;chunk.bytesSent=e.loaded;var fileProgress=0,fileTotal=void 0,fileBytesSent=void 0;file.upload.progress=0;file.upload.total=0;file.upload.bytesSent=0;for(var i=0;i=_iterator26.length)break;_ref25=_iterator26[_i28++];}else{_i28=_iterator26.next();if(_i28.done)break;_ref25=_i28.value;} +var _file2=_ref25;_file2.upload.progress=progress;_file2.upload.total=e.total;_file2.upload.bytesSent=e.loaded;}} +for(var _iterator27=files,_isArray27=true,_i29=0,_iterator27=_isArray27?_iterator27:_iterator27[Symbol.iterator]();;){var _ref26;if(_isArray27){if(_i29>=_iterator27.length)break;_ref26=_iterator27[_i29++];}else{_i29=_iterator27.next();if(_i29.done)break;_ref26=_i29.value;} +var _file3=_ref26;this.emit("uploadprogress",_file3,_file3.upload.progress,_file3.upload.bytesSent);}}else{var allFilesFinished=true;progress=100;for(var _iterator28=files,_isArray28=true,_i30=0,_iterator28=_isArray28?_iterator28:_iterator28[Symbol.iterator]();;){var _ref27;if(_isArray28){if(_i30>=_iterator28.length)break;_ref27=_iterator28[_i30++];}else{_i30=_iterator28.next();if(_i30.done)break;_ref27=_i30.value;} +var _file4=_ref27;if(_file4.upload.progress!==100||_file4.upload.bytesSent!==_file4.upload.total){allFilesFinished=false;} +_file4.upload.progress=progress;_file4.upload.bytesSent=_file4.upload.total;} +if(allFilesFinished){return;} +for(var _iterator29=files,_isArray29=true,_i31=0,_iterator29=_isArray29?_iterator29:_iterator29[Symbol.iterator]();;){var _ref28;if(_isArray29){if(_i31>=_iterator29.length)break;_ref28=_iterator29[_i31++];}else{_i31=_iterator29.next();if(_i31.done)break;_ref28=_i31.value;} +var _file5=_ref28;this.emit("uploadprogress",_file5,progress,_file5.upload.bytesSent);}}}},{key:"_finishedUploading",value:function _finishedUploading(files,xhr,e){var response=void 0;if(files[0].status===Dropzone.CANCELED){return;} +if(xhr.readyState!==4){return;} +if(xhr.responseType!=='arraybuffer'&&xhr.responseType!=='blob'){response=xhr.responseText;if(xhr.getResponseHeader("content-type")&&~xhr.getResponseHeader("content-type").indexOf("application/json")){try{response=JSON.parse(response);}catch(error){e=error;response="Invalid JSON response from server.";}}} +this._updateFilesUploadProgress(files);if(!(200<=xhr.status&&xhr.status<300)){this._handleUploadError(files,xhr,response);}else{if(files[0].upload.chunked){files[0].upload.finishedChunkUpload(this._getChunk(files[0],xhr));}else{this._finished(files,response,e);}}}},{key:"_handleUploadError",value:function _handleUploadError(files,xhr,response){if(files[0].status===Dropzone.CANCELED){return;} +if(files[0].upload.chunked&&this.options.retryChunks){var chunk=this._getChunk(files[0],xhr);if(chunk.retries++=_iterator30.length)break;_ref29=_iterator30[_i32++];}else{_i32=_iterator30.next();if(_i32.done)break;_ref29=_i32.value;} +var file=_ref29;this._errorProcessing(files,response||this.options.dictResponseError.replace("{{statusCode}}",xhr.status),xhr);}}},{key:"submitRequest",value:function submitRequest(xhr,formData,files){xhr.send(formData);}},{key:"_finished",value:function _finished(files,responseText,e){for(var _iterator31=files,_isArray31=true,_i33=0,_iterator31=_isArray31?_iterator31:_iterator31[Symbol.iterator]();;){var _ref30;if(_isArray31){if(_i33>=_iterator31.length)break;_ref30=_iterator31[_i33++];}else{_i33=_iterator31.next();if(_i33.done)break;_ref30=_i33.value;} +var file=_ref30;file.status=Dropzone.SUCCESS;this.emit("success",file,responseText,e);this.emit("complete",file);} if(this.options.uploadMultiple){this.emit("successmultiple",files,responseText,e);this.emit("completemultiple",files);} -if(this.options.autoProcessQueue){return this.processQueue();}};Dropzone.prototype._errorProcessing=function(files,message,xhr){var file,_i,_len;for(_i=0,_len=files.length;_i<_len;_i++){file=files[_i];file.status=Dropzone.ERROR;this.emit("error",file,message,xhr);this.emit("complete",file);} +if(this.options.autoProcessQueue){return this.processQueue();}}},{key:"_errorProcessing",value:function _errorProcessing(files,message,xhr){for(var _iterator32=files,_isArray32=true,_i34=0,_iterator32=_isArray32?_iterator32:_iterator32[Symbol.iterator]();;){var _ref31;if(_isArray32){if(_i34>=_iterator32.length)break;_ref31=_iterator32[_i34++];}else{_i34=_iterator32.next();if(_i34.done)break;_ref31=_i34.value;} +var file=_ref31;file.status=Dropzone.ERROR;this.emit("error",file,message,xhr);this.emit("complete",file);} if(this.options.uploadMultiple){this.emit("errormultiple",files,message,xhr);this.emit("completemultiple",files);} -if(this.options.autoProcessQueue){return this.processQueue();}};return Dropzone;})(Emitter);Dropzone.version="4.0.1";Dropzone.options={};Dropzone.optionsForElement=function(element){if(element.getAttribute("id")){return Dropzone.options[camelize(element.getAttribute("id"))];}else{return void 0;}};Dropzone.instances=[];Dropzone.forElement=function(element){if(typeof element==="string"){element=document.querySelector(element);} -if((element!=null?element.dropzone:void 0)==null){throw new Error("No Dropzone found for given element. This is probably because you're trying to access it before Dropzone had the time to initialize. Use the `init` option to setup any additional observers on your Dropzone.");} -return element.dropzone;};Dropzone.autoDiscover=true;Dropzone.discover=function(){var checkElements,dropzone,dropzones,_i,_len,_results;if(document.querySelectorAll){dropzones=document.querySelectorAll(".dropzone");}else{dropzones=[];checkElements=function(elements){var el,_i,_len,_results;_results=[];for(_i=0,_len=elements.length;_i<_len;_i++){el=elements[_i];if(/(^| )dropzone($| )/.test(el.className)){_results.push(dropzones.push(el));}else{_results.push(void 0);}} -return _results;};checkElements(document.getElementsByTagName("div"));checkElements(document.getElementsByTagName("form"));} -_results=[];for(_i=0,_len=dropzones.length;_i<_len;_i++){dropzone=dropzones[_i];if(Dropzone.optionsForElement(dropzone)!==false){_results.push(new Dropzone(dropzone));}else{_results.push(void 0);}} -return _results;};Dropzone.blacklistedBrowsers=[/opera.*Macintosh.*version\/12/i];Dropzone.isBrowserSupported=function(){var capableBrowser,regex,_i,_len,_ref;capableBrowser=true;if(window.File&&window.FileReader&&window.FileList&&window.Blob&&window.FormData&&document.querySelector){if(!("classList"in document.createElement("a"))){capableBrowser=false;}else{_ref=Dropzone.blacklistedBrowsers;for(_i=0,_len=_ref.length;_i<_len;_i++){regex=_ref[_i];if(regex.test(navigator.userAgent)){capableBrowser=false;continue;}}}}else{capableBrowser=false;} -return capableBrowser;};without=function(list,rejectedItem){var item,_i,_len,_results;_results=[];for(_i=0,_len=list.length;_i<_len;_i++){item=list[_i];if(item!==rejectedItem){_results.push(item);}} -return _results;};camelize=function(str){return str.replace(/[\-_](\w)/g,function(match){return match.charAt(1).toUpperCase();});};Dropzone.createElement=function(string){var div;div=document.createElement("div");div.innerHTML=string;return div.childNodes[0];};Dropzone.elementInside=function(element,container){if(element===container){return true;} +if(this.options.autoProcessQueue){return this.processQueue();}}}],[{key:"uuidv4",value:function uuidv4(){return'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g,function(c){var r=Math.random()*16|0,v=c==='x'?r:r&0x3|0x8;return v.toString(16);});}}]);return Dropzone;}(Emitter);Dropzone.initClass();Dropzone.version="5.5.1";Dropzone.options={};Dropzone.optionsForElement=function(element){if(element.getAttribute("id")){return Dropzone.options[camelize(element.getAttribute("id"))];}else{return undefined;}};Dropzone.instances=[];Dropzone.forElement=function(element){if(typeof element==="string"){element=document.querySelector(element);} +if((element!=null?element.dropzone:undefined)==null){throw new Error("No Dropzone found for given element. This is probably because you're trying to access it before Dropzone had the time to initialize. Use the `init` option to setup any additional observers on your Dropzone.");} +return element.dropzone;};Dropzone.autoDiscover=true;Dropzone.discover=function(){var dropzones=void 0;if(document.querySelectorAll){dropzones=document.querySelectorAll(".dropzone");}else{dropzones=[];var checkElements=function checkElements(elements){return function(){var result=[];for(var _iterator33=elements,_isArray33=true,_i35=0,_iterator33=_isArray33?_iterator33:_iterator33[Symbol.iterator]();;){var _ref32;if(_isArray33){if(_i35>=_iterator33.length)break;_ref32=_iterator33[_i35++];}else{_i35=_iterator33.next();if(_i35.done)break;_ref32=_i35.value;} +var el=_ref32;if(/(^| )dropzone($| )/.test(el.className)){result.push(dropzones.push(el));}else{result.push(undefined);}} +return result;}();};checkElements(document.getElementsByTagName("div"));checkElements(document.getElementsByTagName("form"));} +return function(){var result=[];for(var _iterator34=dropzones,_isArray34=true,_i36=0,_iterator34=_isArray34?_iterator34:_iterator34[Symbol.iterator]();;){var _ref33;if(_isArray34){if(_i36>=_iterator34.length)break;_ref33=_iterator34[_i36++];}else{_i36=_iterator34.next();if(_i36.done)break;_ref33=_i36.value;} +var dropzone=_ref33;if(Dropzone.optionsForElement(dropzone)!==false){result.push(new Dropzone(dropzone));}else{result.push(undefined);}} +return result;}();};Dropzone.blacklistedBrowsers=[/opera.*(Macintosh|Windows Phone).*version\/12/i];Dropzone.isBrowserSupported=function(){var capableBrowser=true;if(window.File&&window.FileReader&&window.FileList&&window.Blob&&window.FormData&&document.querySelector){if(!("classList"in document.createElement("a"))){capableBrowser=false;}else{for(var _iterator35=Dropzone.blacklistedBrowsers,_isArray35=true,_i37=0,_iterator35=_isArray35?_iterator35:_iterator35[Symbol.iterator]();;){var _ref34;if(_isArray35){if(_i37>=_iterator35.length)break;_ref34=_iterator35[_i37++];}else{_i37=_iterator35.next();if(_i37.done)break;_ref34=_i37.value;} +var regex=_ref34;if(regex.test(navigator.userAgent)){capableBrowser=false;continue;}}}}else{capableBrowser=false;} +return capableBrowser;};Dropzone.dataURItoBlob=function(dataURI){var byteString=atob(dataURI.split(',')[1]);var mimeString=dataURI.split(',')[0].split(':')[1].split(';')[0];var ab=new ArrayBuffer(byteString.length);var ia=new Uint8Array(ab);for(var i=0,end=byteString.length,asc=0<=end;asc?i<=end:i>=end;asc?i++:i--){ia[i]=byteString.charCodeAt(i);} +return new Blob([ab],{type:mimeString});};var without=function without(list,rejectedItem){return list.filter(function(item){return item!==rejectedItem;}).map(function(item){return item;});};var camelize=function camelize(str){return str.replace(/[\-_](\w)/g,function(match){return match.charAt(1).toUpperCase();});};Dropzone.createElement=function(string){var div=document.createElement("div");div.innerHTML=string;return div.childNodes[0];};Dropzone.elementInside=function(element,container){if(element===container){return true;} while(element=element.parentNode){if(element===container){return true;}} -return false;};Dropzone.getElement=function(el,name){var element;if(typeof el==="string"){element=document.querySelector(el);}else if(el.nodeType!=null){element=el;} +return false;};Dropzone.getElement=function(el,name){var element=void 0;if(typeof el==="string"){element=document.querySelector(el);}else if(el.nodeType!=null){element=el;} if(element==null){throw new Error("Invalid `"+name+"` option provided. Please provide a CSS selector or a plain HTML element.");} -return element;};Dropzone.getElements=function(els,name){var e,el,elements,_i,_j,_len,_len1,_ref;if(els instanceof Array){elements=[];try{for(_i=0,_len=els.length;_i<_len;_i++){el=els[_i];elements.push(this.getElement(el,name));}}catch(_error){e=_error;elements=null;}}else if(typeof els==="string"){elements=[];_ref=document.querySelectorAll(els);for(_j=0,_len1=_ref.length;_j<_len1;_j++){el=_ref[_j];elements.push(el);}}else if(els.nodeType!=null){elements=[els];} -if(!((elements!=null)&&elements.length)){throw new Error("Invalid `"+name+"` option provided. Please provide a CSS selector, a plain HTML element or a list of those.");} -return elements;};Dropzone.confirm=function(question,accepted,rejected){if(window.confirm(question)){return accepted();}else if(rejected!=null){return rejected();}};Dropzone.isValidFile=function(file,acceptedFiles){var baseMimeType,mimeType,validType,_i,_len;if(!acceptedFiles){return true;} -acceptedFiles=acceptedFiles.split(",");mimeType=file.type;baseMimeType=mimeType.replace(/\/.*$/,"");for(_i=0,_len=acceptedFiles.length;_i<_len;_i++){validType=acceptedFiles[_i];validType=validType.trim();if(validType.charAt(0)==="."){if(file.name.toLowerCase().indexOf(validType.toLowerCase(),file.name.length-validType.length)!==-1){return true;}}else if(/\/\*$/.test(validType)){if(baseMimeType===validType.replace(/\/.*$/,"")){return true;}}else{if(mimeType===validType){return true;}}} -return false;};if(typeof jQuery!=="undefined"&&jQuery!==null){jQuery.fn.dropzone=function(options){return this.each(function(){return new Dropzone(this,options);});};} -if(typeof module!=="undefined"&&module!==null){module.exports=Dropzone;}else{window.Dropzone=Dropzone;} -Dropzone.ADDED="added";Dropzone.QUEUED="queued";Dropzone.ACCEPTED=Dropzone.QUEUED;Dropzone.UPLOADING="uploading";Dropzone.PROCESSING=Dropzone.UPLOADING;Dropzone.CANCELED="canceled";Dropzone.ERROR="error";Dropzone.SUCCESS="success";detectVerticalSquash=function(img){var alpha,canvas,ctx,data,ey,ih,iw,py,ratio,sy;iw=img.naturalWidth;ih=img.naturalHeight;canvas=document.createElement("canvas");canvas.width=1;canvas.height=ih;ctx=canvas.getContext("2d");ctx.drawImage(img,0,0);data=ctx.getImageData(0,0,1,ih).data;sy=0;ey=ih;py=ih;while(py>sy){alpha=data[(py-1)*4+3];if(alpha===0){ey=py;}else{sy=py;} -py=(ey+sy)>>1;} -ratio=py/ih;if(ratio===0){return 1;}else{return ratio;}};drawImageIOSFix=function(ctx,img,sx,sy,sw,sh,dx,dy,dw,dh){var vertSquashRatio;vertSquashRatio=detectVerticalSquash(img);return ctx.drawImage(img,sx,sy,sw,sh,dx,dy,dw,dh/vertSquashRatio);};contentLoaded=function(win,fn){var add,doc,done,init,poll,pre,rem,root,top;done=false;top=true;doc=win.document;root=doc.documentElement;add=(doc.addEventListener?"addEventListener":"attachEvent");rem=(doc.addEventListener?"removeEventListener":"detachEvent");pre=(doc.addEventListener?"":"on");init=function(e){if(e.type==="readystatechange"&&doc.readyState!=="complete"){return;} -(e.type==="load"?win:doc)[rem](pre+e.type,init,false);if(!done&&(done=true)){return fn.call(win,e.type||e);}};poll=function(){var e;try{root.doScroll("left");}catch(_error){e=_error;setTimeout(poll,50);return;} -return init("poll");};if(doc.readyState!=="complete"){if(doc.createEventObject&&root.doScroll){try{top=!win.frameElement;}catch(_error){} +return element;};Dropzone.getElements=function(els,name){var el=void 0,elements=void 0;if(els instanceof Array){elements=[];try{for(var _iterator36=els,_isArray36=true,_i38=0,_iterator36=_isArray36?_iterator36:_iterator36[Symbol.iterator]();;){if(_isArray36){if(_i38>=_iterator36.length)break;el=_iterator36[_i38++];}else{_i38=_iterator36.next();if(_i38.done)break;el=_i38.value;} +elements.push(this.getElement(el,name));}}catch(e){elements=null;}}else if(typeof els==="string"){elements=[];for(var _iterator37=document.querySelectorAll(els),_isArray37=true,_i39=0,_iterator37=_isArray37?_iterator37:_iterator37[Symbol.iterator]();;){if(_isArray37){if(_i39>=_iterator37.length)break;el=_iterator37[_i39++];}else{_i39=_iterator37.next();if(_i39.done)break;el=_i39.value;} +elements.push(el);}}else if(els.nodeType!=null){elements=[els];} +if(elements==null||!elements.length){throw new Error("Invalid `"+name+"` option provided. Please provide a CSS selector, a plain HTML element or a list of those.");} +return elements;};Dropzone.confirm=function(question,accepted,rejected){if(window.confirm(question)){return accepted();}else if(rejected!=null){return rejected();}};Dropzone.isValidFile=function(file,acceptedFiles){if(!acceptedFiles){return true;} +acceptedFiles=acceptedFiles.split(",");var mimeType=file.type;var baseMimeType=mimeType.replace(/\/.*$/,"");for(var _iterator38=acceptedFiles,_isArray38=true,_i40=0,_iterator38=_isArray38?_iterator38:_iterator38[Symbol.iterator]();;){var _ref35;if(_isArray38){if(_i40>=_iterator38.length)break;_ref35=_iterator38[_i40++];}else{_i40=_iterator38.next();if(_i40.done)break;_ref35=_i40.value;} +var validType=_ref35;validType=validType.trim();if(validType.charAt(0)==="."){if(file.name.toLowerCase().indexOf(validType.toLowerCase(),file.name.length-validType.length)!==-1){return true;}}else if(/\/\*$/.test(validType)){if(baseMimeType===validType.replace(/\/.*$/,"")){return true;}}else{if(mimeType===validType){return true;}}} +return false;};if(typeof jQuery!=='undefined'&&jQuery!==null){jQuery.fn.dropzone=function(options){return this.each(function(){return new Dropzone(this,options);});};} +if(typeof module!=='undefined'&&module!==null){module.exports=Dropzone;}else{window.Dropzone=Dropzone;} +Dropzone.ADDED="added";Dropzone.QUEUED="queued";Dropzone.ACCEPTED=Dropzone.QUEUED;Dropzone.UPLOADING="uploading";Dropzone.PROCESSING=Dropzone.UPLOADING;Dropzone.CANCELED="canceled";Dropzone.ERROR="error";Dropzone.SUCCESS="success";var detectVerticalSquash=function detectVerticalSquash(img){var iw=img.naturalWidth;var ih=img.naturalHeight;var canvas=document.createElement("canvas");canvas.width=1;canvas.height=ih;var ctx=canvas.getContext("2d");ctx.drawImage(img,0,0);var _ctx$getImageData=ctx.getImageData(1,0,1,ih),data=_ctx$getImageData.data;var sy=0;var ey=ih;var py=ih;while(py>sy){var alpha=data[(py-1)*4+3];if(alpha===0){ey=py;}else{sy=py;} +py=ey+sy>>1;} +var ratio=py/ih;if(ratio===0){return 1;}else{return ratio;}};var drawImageIOSFix=function drawImageIOSFix(ctx,img,sx,sy,sw,sh,dx,dy,dw,dh){var vertSquashRatio=detectVerticalSquash(img);return ctx.drawImage(img,sx,sy,sw,sh,dx,dy,dw,dh/vertSquashRatio);};var ExifRestore=function(){function ExifRestore(){_classCallCheck(this,ExifRestore);} +_createClass(ExifRestore,null,[{key:"initClass",value:function initClass(){this.KEY_STR='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';}},{key:"encode64",value:function encode64(input){var output='';var chr1=undefined;var chr2=undefined;var chr3='';var enc1=undefined;var enc2=undefined;var enc3=undefined;var enc4='';var i=0;while(true){chr1=input[i++];chr2=input[i++];chr3=input[i++];enc1=chr1>>2;enc2=(chr1&3)<<4|chr2>>4;enc3=(chr2&15)<<2|chr3>>6;enc4=chr3&63;if(isNaN(chr2)){enc3=enc4=64;}else if(isNaN(chr3)){enc4=64;} +output=output+this.KEY_STR.charAt(enc1)+this.KEY_STR.charAt(enc2)+this.KEY_STR.charAt(enc3)+this.KEY_STR.charAt(enc4);chr1=chr2=chr3='';enc1=enc2=enc3=enc4='';if(!(irawImageArray.length){break;}} +return segments;}},{key:"decode64",value:function decode64(input){var output='';var chr1=undefined;var chr2=undefined;var chr3='';var enc1=undefined;var enc2=undefined;var enc3=undefined;var enc4='';var i=0;var buf=[];var base64test=/[^A-Za-z0-9\+\/\=]/g;if(base64test.exec(input)){console.warn('There were invalid base64 characters in the input text.\nValid base64 characters are A-Z, a-z, 0-9, \'+\', \'/\',and \'=\'\nExpect errors in decoding.');} +input=input.replace(/[^A-Za-z0-9\+\/\=]/g,'');while(true){enc1=this.KEY_STR.indexOf(input.charAt(i++));enc2=this.KEY_STR.indexOf(input.charAt(i++));enc3=this.KEY_STR.indexOf(input.charAt(i++));enc4=this.KEY_STR.indexOf(input.charAt(i++));chr1=enc1<<2|enc2>>4;chr2=(enc2&15)<<4|enc3>>2;chr3=(enc3&3)<<6|enc4;buf.push(chr1);if(enc3!==64){buf.push(chr2);} +if(enc4!==64){buf.push(chr3);} +chr1=chr2=chr3='';enc1=enc2=enc3=enc4='';if(!(i=0){newClass=newClass.replace(' '+className+' ',' ');} +doc[add](pre+"DOMContentLoaded",init,false);doc[add](pre+"readystatechange",init,false);return win[add](pre+"load",init,false);}};Dropzone._autoDiscoverFunction=function(){if(Dropzone.autoDiscover){return Dropzone.discover();}};contentLoaded(window,Dropzone._autoDiscoverFunction);function __guard__(value,transform){return typeof value!=='undefined'&&value!==null?transform(value):undefined;} +function __guardMethod__(obj,methodName,transform){if(typeof obj!=='undefined'&&obj!==null&&typeof obj[methodName]==='function'){return transform(obj,methodName);}else{return undefined;}} +(function(window,document){var modalClass='.sweet-alert',overlayClass='.sweet-overlay',alertTypes=['error','warning','info','success'],defaultParams={title:'',text:'',type:null,allowOutsideClick:false,showCancelButton:false,showConfirmButton:true,closeOnConfirm:true,closeOnCancel:true,confirmButtonText:'OK',confirmButtonClass:'btn-primary',cancelButtonText:'Cancel',cancelButtonClass:'btn-default',containerClass:'',titleClass:'',textClass:'',imageUrl:null,imageSize:null,timer:null};var getModal=function(){return document.querySelector(modalClass);},getOverlay=function(){return document.querySelector(overlayClass);},hasClass=function(elem,className){return new RegExp(' '+className+' ').test(' '+elem.className+' ');},addClass=function(elem,className){if(className&&!hasClass(elem,className)){elem.className+=' '+className;}},removeClass=function(elem,className){var newClass=' '+elem.className.replace(/[\t\r\n]/g,' ')+' ';if(hasClass(elem,className)){while(newClass.indexOf(' '+className+' ')>=0){newClass=newClass.replace(' '+className+' ',' ');} elem.className=newClass.replace(/^\s+|\s+$/g,'');}},escapeHtml=function(str){var div=document.createElement('div');div.appendChild(document.createTextNode(str));return div.innerHTML;},_show=function(elem){elem.style.opacity='';elem.style.display='block';},show=function(elems){if(elems&&!elems.length){return _show(elems);} for(var i=0;iul >li >a {color:#666} -.field-codeeditor.editor-fullscreen .editor-toolbar >ul >li >a:hover >i, -.field-codeeditor.editor-fullscreen .editor-toolbar >ul >li >a:focus >i {color:#191919} +.field-codeeditor.editor-fullscreen .editor-toolbar >ul >li >a:hover, +.field-codeeditor.editor-fullscreen .editor-toolbar >ul >li >a:focus {color:#191919} .field-codeeditor.editor-fullscreen .ace_search {z-index:303} .field-codeeditor .secondary-tabs .editor-toolbar >ul >li >a {color:#fff} #cms-master-tabs .field-codeeditor .editor-toolbar >ul >li >a {color:#919898} \ No newline at end of file diff --git a/modules/backend/formwidgets/fileupload/assets/css/fileupload.css b/modules/backend/formwidgets/fileupload/assets/css/fileupload.css index 3636e42643..b3d4ba1746 100644 --- a/modules/backend/formwidgets/fileupload/assets/css/fileupload.css +++ b/modules/backend/formwidgets/fileupload/assets/css/fileupload.css @@ -16,7 +16,7 @@ .field-fileupload .upload-object .icon-container:after {background-image:url('../../../../../system/assets/ui/images/loader-transparent.svg');position:absolute;content:' ';width:40px;height:40px;left:50%;top:50%;margin-top:-20px;margin-left:-20px;display:block;background-size:40px 40px;background-position:50% 50%;-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite} .field-fileupload .upload-object.is-success .icon-container {opacity:1} .field-fileupload .upload-object.is-success .icon-container:after {opacity:0;-webkit-transition:opacity 0.3s ease;transition:opacity 0.3s ease} -.field-fileupload .upload-object.is-error .icon-container:after {content:"";background:none;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f071";-webkit-animation:none;animation:none;font-size:40px;color:#ab2a1c;margin-top:-20px;margin-left:-20px;text-shadow:2px 2px 0 #fff} +.field-fileupload .upload-object.is-error .icon-container:after {content:"";background:none;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f071";-webkit-animation:none;animation:none;font-size:40px;color:#ab2a1c;margin-top:-20px;margin-left:-20px;text-shadow:2px 2px 0 #fff} .field-fileupload .upload-object.is-loading .icon-container {opacity:.6} .field-fileupload .upload-object.is-loading .icon-container:after {opacity:1;-webkit-transition:opacity 0.3s ease;transition:opacity 0.3s ease} .field-fileupload .upload-object.is-success {cursor:pointer} diff --git a/modules/backend/formwidgets/repeater/assets/css/repeater.css b/modules/backend/formwidgets/repeater/assets/css/repeater.css index 604603da08..f12d273770 100644 --- a/modules/backend/formwidgets/repeater/assets/css/repeater.css +++ b/modules/backend/formwidgets/repeater/assets/css/repeater.css @@ -6,9 +6,9 @@ .field-repeater ul.field-repeater-items >li.dragged .repeater-item-remove {opacity:0} .field-repeater ul.field-repeater-items >li.dragged .repeater-item-collapsed-title {top:5px} .field-repeater ul.field-repeater-items >li.placeholder {display:block;position:relative;height:25px;margin-bottom:5px} -.field-repeater ul.field-repeater-items >li.placeholder:before {display:block;position:absolute;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f054";color:#d35714;left:-10px;top:8px;z-index:2000} +.field-repeater ul.field-repeater-items >li.placeholder:before {display:block;position:absolute;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f054";color:#d35714;left:-10px;top:8px;z-index:2000} .field-repeater li.field-repeater-item {position:relative;margin:0 0 1em 1em !important;padding:1.5em 1.25em 0 1.25em !important;background:#f5f5f5;border:1px solid #d1d6d9;border-radius:3px;box-shadow:inset 0 1px 0 rgba(209,214,217,0.25),0 1px 0 rgba(255,255,255,.5);min-height:30px} -.field-repeater li.field-repeater-item:before {color:#bdc3c7;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f111";font-size:8px;position:absolute;left:-18px;top:-2px} +.field-repeater li.field-repeater-item:before {color:#bdc3c7;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f111";font-size:8px;position:absolute;left:-18px;top:-2px} .field-repeater li.field-repeater-item:after {counter-increment:repeater-index-counter;content:counter(repeater-index-counter);display:block;position:absolute;font-size:12px;left:-27px;color:#bdc3c7;top:10px;width:24px;text-align:center} .field-repeater li.field-repeater-item.collapsed .field-repeater-form {display:none} .field-repeater li.field-repeater-item.collapsed .repeater-item-collapse .repeater-item-collapse-one {-webkit-transform:scale(1,-1);-ms-transform:scale(1,-1);transform:scale(1,-1)} @@ -41,7 +41,7 @@ .field-repeater li.field-repeater-item:hover .repeater-item-remove, .field-repeater li.field-repeater-item:active .repeater-item-remove {opacity:1} .field-repeater .field-repeater-add-item {position:relative;margin-top:10px;margin-left:20px;border:2px dotted #e0e0e0;border-radius:5px} -.field-repeater .field-repeater-add-item:before {color:#bdc3c7;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f067";font-size:16px;position:absolute;left:-23px;top:-11px} +.field-repeater .field-repeater-add-item:before {color:#bdc3c7;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f067";font-size:16px;position:absolute;left:-23px;top:-11px} .field-repeater .field-repeater-add-item >a {color:#bdc3c7;text-align:center;display:block;text-decoration:none;padding:13px 15px;text-transform:uppercase;font-weight:600;font-size:12px} .field-repeater .field-repeater-add-item:hover, .field-repeater .field-repeater-add-item:focus {background-color:#4ea5e0;border-color:transparent} diff --git a/modules/backend/formwidgets/richeditor/assets/css/richeditor.css b/modules/backend/formwidgets/richeditor/assets/css/richeditor.css index 57e7057885..aa368cccf0 100755 --- a/modules/backend/formwidgets/richeditor/assets/css/richeditor.css +++ b/modules/backend/formwidgets/richeditor/assets/css/richeditor.css @@ -562,6 +562,6 @@ body .fr-popup .fr-checkbox span {border-color:#d1d6d9} .control-richeditor figure[data-audio]:after {content:attr(data-label)} .control-richeditor figure[data-video]:before, .control-richeditor figure[data-audio]:before {position:static;margin-right:8px} -.control-richeditor figure[data-video]:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f03d"} -.control-richeditor figure[data-audio]:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f028"} +.control-richeditor figure[data-video]:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f03d"} +.control-richeditor figure[data-audio]:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f028"} .fr-quick-insert a.fr-floating-btn {color:rgba(64,82,97,0.8);text-decoration:none} \ No newline at end of file diff --git a/modules/system/assets/css/styles.css b/modules/system/assets/css/styles.css index 9abb752c2f..713fddb5cb 100644 --- a/modules/system/assets/css/styles.css +++ b/modules/system/assets/css/styles.css @@ -1937,7 +1937,7 @@ address {margin-bottom:20px;font-style:normal;line-height:1.42857143} button.close {padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none} @font-face {font-family:'FontAwesome';src:url('../ui/font/fontawesome-webfont.eot?v=1.0.1');src:url('../ui/font/fontawesome-webfont.eot?#iefix&v=1.0.1') format('embedded-opentype'),url('../ui/font/fontawesome-webfont.woff?v=1.0.1') format('woff'),url('../ui/font/fontawesome-webfont.ttf?v=1.0.1') format('truetype'),url('../ui/font/fontawesome-webfont.svg#fontawesomeregular?v=1.0.1') format('svg');font-weight:normal;font-style:normal} [class^="icon-"], -[class*=" icon-"] {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;display:inline;width:auto;height:auto;line-height:normal;vertical-align:baseline;background-image:none;background-position:0% 0%;background-repeat:repeat;margin-top:0} +[class*=" icon-"] {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;display:inline;width:auto;height:auto;line-height:normal;vertical-align:baseline;background-image:none;background-position:0% 0%;background-repeat:repeat;margin-top:0} [class^="icon-"]:before, [class*=" icon-"]:before {text-decoration:inherit;display:inline-block;speak:none} [class^="icon-"].pull-left, @@ -1945,7 +1945,7 @@ button.close {padding:0;cursor:pointer;background:transparent;border:0;-webkit-a [class^="icon-"].pull-right, [class*=" icon-"].pull-right {margin-left:.3em} [class^="oc-icon-"]:before, -[class*=" oc-icon-"]:before {display:inline-block;margin-right:8px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;vertical-align:baseline} +[class*=" oc-icon-"]:before {display:inline-block;margin-right:8px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;vertical-align:baseline} [class^="oc-icon-"].empty:before, [class*=" oc-icon-"].empty:before {margin-right:0} .icon-lg {font-size:1.33333333em;line-height:0.75em;vertical-align:-15%} diff --git a/modules/system/assets/ui/storm.css b/modules/system/assets/ui/storm.css index e3e294e813..73de67aa1e 100644 --- a/modules/system/assets/ui/storm.css +++ b/modules/system/assets/ui/storm.css @@ -2509,7 +2509,7 @@ input[type="button"].btn-block {width:100%} button.close {padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none} @font-face {font-family:'FontAwesome';src:url('font/fontawesome-webfont.eot?v=1.0.1');src:url('font/fontawesome-webfont.eot?#iefix&v=1.0.1') format('embedded-opentype'),url('font/fontawesome-webfont.woff?v=1.0.1') format('woff'),url('font/fontawesome-webfont.ttf?v=1.0.1') format('truetype'),url('font/fontawesome-webfont.svg#fontawesomeregular?v=1.0.1') format('svg');font-weight:normal;font-style:normal} [class^="icon-"], -[class*=" icon-"] {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;display:inline;width:auto;height:auto;line-height:normal;vertical-align:baseline;background-image:none;background-position:0% 0%;background-repeat:repeat;margin-top:0} +[class*=" icon-"] {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;display:inline;width:auto;height:auto;line-height:normal;vertical-align:baseline;background-image:none;background-position:0% 0%;background-repeat:repeat;margin-top:0} [class^="icon-"]:before, [class*=" icon-"]:before {text-decoration:inherit;display:inline-block;speak:none} [class^="icon-"].pull-left, @@ -2517,7 +2517,7 @@ button.close {padding:0;cursor:pointer;background:transparent;border:0;-webkit-a [class^="icon-"].pull-right, [class*=" icon-"].pull-right {margin-left:.3em} [class^="oc-icon-"]:before, -[class*=" oc-icon-"]:before {display:inline-block;margin-right:8px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;vertical-align:baseline} +[class*=" oc-icon-"]:before {display:inline-block;margin-right:8px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;vertical-align:baseline} [class^="oc-icon-"].empty:before, [class*=" oc-icon-"].empty:before {margin-right:0} .icon-lg {font-size:1.33333333em;line-height:0.75em;vertical-align:-15%} @@ -2593,7 +2593,7 @@ button.close {padding:0;cursor:pointer;background:transparent;border:0;-webkit-a .touch .dropdown-menu .dropdown-container >ul li a:hover:before {position:absolute;font-size:14px;left:9px;top:7px;color:rgba(0,0,0,0.2)} .touch .dropdown-menu .dropdown-container >ul li.first-item a:hover:after {content:'';display:none} body.dropdown-open .dropdown-overlay {position:fixed;left:0;top:0;right:0;bottom:0;z-index:599} -@media (max-width:480px) {body.dropdown-open {overflow:hidden }body.dropdown-open .dropdown-overlay {background:rgba(0,0,0,0.4) }body.dropdown-open .dropdown-menu {overflow:auto;overflow-y:scroll;position:fixed !important;margin:0 !important;top:0 !important;right:0 !important;bottom:0 !important;left:0 !important;z-index:600 }body.dropdown-open .dropdown-menu .dropdown-container {padding:10px;height:100% }body.dropdown-open .dropdown-menu .dropdown-container ul {min-height:100%;margin-top:0 }body.dropdown-open .dropdown-menu .dropdown-container ul:before,body.dropdown-open .dropdown-menu .dropdown-container ul:after {display:none }body.dropdown-open .dropdown-menu .dropdown-container ul li.dropdown-title {display:block;padding:8px 15px;border-bottom:1px solid #c9c9c9;color:#39454a;position:relative;cursor:pointer;font-weight:600 }body.dropdown-open .dropdown-menu .dropdown-container ul li.dropdown-title:after {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f00d";position:absolute;top:7px;right:13px;opacity:0.3;filter:alpha(opacity=30) }body.dropdown-open .dropdown-menu .dropdown-container ul li.first-item a:hover:after,body.dropdown-open .dropdown-menu .dropdown-container ul li.first-item :focus:after {content:'';display:none }} +@media (max-width:480px) {body.dropdown-open {overflow:hidden }body.dropdown-open .dropdown-overlay {background:rgba(0,0,0,0.4) }body.dropdown-open .dropdown-menu {overflow:auto;overflow-y:scroll;position:fixed !important;margin:0 !important;top:0 !important;right:0 !important;bottom:0 !important;left:0 !important;z-index:600 }body.dropdown-open .dropdown-menu .dropdown-container {padding:10px;height:100% }body.dropdown-open .dropdown-menu .dropdown-container ul {min-height:100%;margin-top:0 }body.dropdown-open .dropdown-menu .dropdown-container ul:before,body.dropdown-open .dropdown-menu .dropdown-container ul:after {display:none }body.dropdown-open .dropdown-menu .dropdown-container ul li.dropdown-title {display:block;padding:8px 15px;border-bottom:1px solid #c9c9c9;color:#39454a;position:relative;cursor:pointer;font-weight:600 }body.dropdown-open .dropdown-menu .dropdown-container ul li.dropdown-title:after {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f00d";position:absolute;top:7px;right:13px;opacity:0.3;filter:alpha(opacity=30) }body.dropdown-open .dropdown-menu .dropdown-container ul li.first-item a:hover:after,body.dropdown-open .dropdown-menu .dropdown-container ul li.first-item :focus:after {content:'';display:none }} div.control-popover {position:absolute;background-clip:content-box;left:0;top:0;z-index:600;visibility:hidden} div.control-popover.in, div.control-popover.fade {visibility:visible} @@ -2781,8 +2781,8 @@ body.compact-container .control-breadcrumb {margin-top:0;margin-left:0;margin-ri .control-tabs:last-child {margin-bottom:0} .control-tabs:after, .control-tabs:before {display:none;position:absolute;top:50%;margin-top:-7px;height:9px;font-size:10px;color:#bbb} -.control-tabs:before {left:-6px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f104"} -.control-tabs:after {right:-8px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f105"} +.control-tabs:before {left:-6px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f104"} +.control-tabs:after {right:-8px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f105"} .control-tabs.scroll-before:before {display:block} .control-tabs.scroll-after:after {display:block} .control-tabs.scroll-active-before:before {color:#d0d0d0} @@ -3002,9 +3002,9 @@ body.compact-container .control-breadcrumb {margin-top:0;margin-left:0;margin-ri .title-value p.negative:after, .title-value p.positive:after {font-size:17px;vertical-align:top;position:relative;top:-3px;left:5px} .title-value p.negative {color:#c30} -.title-value p.negative:after {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f103"} +.title-value p.negative:after {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f103"} .title-value p.positive {color:#95b753} -.title-value p.positive:after {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f102"} +.title-value p.positive:after {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f102"} .title-value p.description {color:#999;font-weight:300;line-height:100%;font-size:13px} .report-container .title-value {margin-top:-18px} .report-container .title-value p {font-weight:100;font-size:40px} @@ -3054,8 +3054,8 @@ a.control-status-list >ul li .status-text.danger:hover {color:#843534} .control-toolbar {font-size:0;padding:0 0 20px 0;position:relative;display:table;table-layout:fixed;width:100%} .control-toolbar:after, .control-toolbar:before {display:none;position:absolute;top:50%;margin-top:-7px;height:9px;font-size:10px;color:#bbb} -.control-toolbar:before {left:-6px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f104"} -.control-toolbar:after {right:-8px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f105"} +.control-toolbar:before {left:-6px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f104"} +.control-toolbar:after {right:-8px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f105"} .control-toolbar.scroll-before:before {display:block} .control-toolbar.scroll-after:after {display:block} .control-toolbar:before {left:-10px} @@ -3065,8 +3065,8 @@ a.control-status-list >ul li .status-text.danger:hover {color:#843534} .control-toolbar .toolbar-item.last {padding-right:0} .control-toolbar .toolbar-item:after, .control-toolbar .toolbar-item:before {display:none;position:absolute;top:50%;margin-top:-7px;height:9px;font-size:10px;color:#bbb} -.control-toolbar .toolbar-item:before {left:-6px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f104"} -.control-toolbar .toolbar-item:after {right:-8px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f105"} +.control-toolbar .toolbar-item:before {left:-6px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f104"} +.control-toolbar .toolbar-item:after {right:-8px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f105"} .control-toolbar .toolbar-item.scroll-before:before {display:block} .control-toolbar .toolbar-item.scroll-after:after {display:block} .control-toolbar .toolbar-item:before {left:-10px} @@ -3130,8 +3130,8 @@ html.mobile [data-control=toolbar].is-native-drag {overflow:auto;-webkit-overflo div.scoreboard {position:relative;padding:0} div.scoreboard:after, div.scoreboard:before {display:none;position:absolute;top:50%;margin-top:-7px;height:9px;font-size:10px;color:#bbb} -div.scoreboard:before {left:-6px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f104"} -div.scoreboard:after {right:-8px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f105"} +div.scoreboard:before {left:-6px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f104"} +div.scoreboard:after {right:-8px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f105"} div.scoreboard.scroll-before:before {display:block} div.scoreboard.scroll-after:after {display:block} div.scoreboard:before, @@ -3943,7 +3943,7 @@ html.cssanimations .cursor-loading-indicator.hide {display:none} .select2-container--default {display:block} .select2-container--default .select2-selection {background-color:#fff;border:1px solid #d1d6d9;border-radius:3px;color:#385487;font-size:14px;-webkit-box-shadow:inset 0 1px 0 rgba(209,214,217,0.25),0 1px 0 rgba(255,255,255,.5);box-shadow:inset 0 1px 0 rgba(209,214,217,0.25),0 1px 0 rgba(255,255,255,.5);outline:0} .select2-container--default .select2-search--dropdown {position:relative} -.select2-container--default .select2-search--dropdown:after {position:absolute;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f002";right:13px;top:9px;color:#95a5a6} +.select2-container--default .select2-search--dropdown:after {position:absolute;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f002";right:13px;top:9px;color:#95a5a6} .select2-container--default .select2-search--dropdown .select2-search__field {background-color:#fff;border:1px solid #d1d6d9;border-radius:3px;color:#385487;font-size:14px;-webkit-box-shadow:inset 0 1px 0 rgba(209,214,217,0.25),0 1px 0 rgba(255,255,255,.5);box-shadow:inset 0 1px 0 rgba(209,214,217,0.25),0 1px 0 rgba(255,255,255,.5)} .select2-container--default .select2-search__field {outline:0} .select2-container--default .select2-search__field::-webkit-input-placeholder {color:#ccc} @@ -3964,7 +3964,7 @@ html.cssanimations .cursor-loading-indicator.hide {display:none} .select2-container--default .select2-results__group {color:#999;display:block;padding:8px 6px;line-height:1.42857143;white-space:nowrap;font-weight:500} .select2-container--default.select2-container--focus .select2-selection, .select2-container--default.select2-container--open .select2-selection {-webkit-transition:border-color ease-in-out 0.15s,box-shadow ease-in-out 0.15s;transition:border-color ease-in-out 0.15s,box-shadow ease-in-out 0.15s;border-color:#d1d6d9} -.select2-container--default.select2-container--open .select2-selection .select2-selection__arrow b:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f106"} +.select2-container--default.select2-container--open .select2-selection .select2-selection__arrow b:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f106"} .select2-container--default.select2-container--open.select2-container--below .select2-selection:not(.select-no-dropdown) {border-bottom-right-radius:0;border-bottom-left-radius:0;border-bottom-color:transparent} .select2-container--default.select2-container--open.select2-container--above .select2-selection:not(.select-no-dropdown) {border-top-right-radius:0;border-top-left-radius:0;border-top-color:transparent} .select2-container--default .select2-selection__clear {color:#666;cursor:pointer;float:right;font-weight:bold;margin-right:10px} @@ -3984,7 +3984,7 @@ html.cssanimations .cursor-loading-indicator.hide {display:none} .select2-container--default .select2-selection--single {height:38px;line-height:1.42857143;padding:8px 25px 8px 13px} .select2-container--default .select2-selection--single .select2-selection__arrow {position:absolute;bottom:0;right:13px;top:0;width:4px} .select2-container--default .select2-selection--single .select2-selection__arrow b {position:absolute;top:50%;height:9px;width:8px;right:3px;margin-top:-5px;line-height:9px} -.select2-container--default .select2-selection--single .select2-selection__arrow b:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f107";display:inline-block} +.select2-container--default .select2-selection--single .select2-selection__arrow b:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f107";display:inline-block} .select2-container--default .select2-selection--single .select2-selection__rendered {color:#385487;padding:0} .select2-container--default .select2-selection--single .select2-selection__placeholder {color:#ccc} .select2-container--default .select2-selection--multiple {min-height:38px} @@ -4114,9 +4114,9 @@ html.cssanimations .cursor-loading-indicator.hide {display:none} .custom-checkbox input[type=checkbox]:checked + label:before, .custom-radio input[type=checkbox]:checked + label:before {border-color:#1f99dc;background-color:#1f99dc;font-size:12px;line-height:17px;border-width:2px;-webkit-box-shadow:none;box-shadow:none} .custom-checkbox input[type=checkbox]:checked + label:before, -.custom-radio input[type=checkbox]:checked + label:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f00c"} +.custom-radio input[type=checkbox]:checked + label:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f00c"} .custom-checkbox input[type=checkbox]:indeterminate + label:before, -.custom-radio input[type=checkbox]:indeterminate + label:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f068"} +.custom-radio input[type=checkbox]:indeterminate + label:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f068"} .custom-checkbox input:disabled + label:before, .custom-radio input:disabled + label:before {border:1px solid #d1d6d9 !important} .custom-checkbox input:disabled:checked + label:before, @@ -4226,7 +4226,7 @@ html.cssanimations .cursor-loading-indicator.hide {display:none} .field-section >p:first-child, .field-section >h4:first-child {margin:0} .field-section.is-collapsible {cursor:pointer} -.field-section.is-collapsible >h4:before {display:inline-block;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;vertical-align:baseline;content:"\f077";font-size:12px;margin:2px 8px 0;float:right;color:rgba(0,0,0,0.4);-webkit-transition:all 0.3s;transition:all 0.3s;-webkit-transform:scale(1,1);-moz-transform:scale(1,1);-ms-transform:scale(1,1);-o-transform:scale(1,1);transform:scale(1,1)} +.field-section.is-collapsible >h4:before {display:inline-block;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;vertical-align:baseline;content:"\f077";font-size:12px;margin:2px 8px 0;float:right;color:rgba(0,0,0,0.4);-webkit-transition:all 0.3s;transition:all 0.3s;-webkit-transform:scale(1,1);-moz-transform:scale(1,1);-ms-transform:scale(1,1);-o-transform:scale(1,1);transform:scale(1,1)} .field-section.is-collapsible:hover {border-bottom:1px solid #b5bdc2} .field-section.is-collapsible:hover >h4:before {color:inherit} .form-group.section-field.collapsed .field-section.is-collapsible >h4:before {-webkit-transform:scale(1,-1);-moz-transform:scale(1,-1);-ms-transform:scale(1,-1);-o-transform:scale(1,-1);transform:scale(1,-1)} @@ -4418,7 +4418,7 @@ table.table.data thead th >span:hover {color:#000} table.table.data thead td.sort-desc >span:after, table.table.data thead th.sort-desc >span:after, table.table.data thead td.sort-desc >a:after, -table.table.data thead th.sort-desc >a:after {font-size:14px;line-height:14px;display:inline-block;margin-left:6px;vertical-align:baseline;opacity:0.4;filter:alpha(opacity=40);font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f107"} +table.table.data thead th.sort-desc >a:after {font-size:14px;line-height:14px;display:inline-block;margin-left:6px;vertical-align:baseline;opacity:0.4;filter:alpha(opacity=40);font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f107"} table.table.data thead td.sort-desc >span:hover:after, table.table.data thead th.sort-desc >span:hover:after, table.table.data thead td.sort-desc >a:hover:after, @@ -4426,7 +4426,7 @@ table.table.data thead th.sort-desc >a:hover:after {opacity:0.8;filter:alpha(opa table.table.data thead td.sort-asc >span:after, table.table.data thead th.sort-asc >span:after, table.table.data thead td.sort-asc >a:after, -table.table.data thead th.sort-asc >a:after {font-size:14px;line-height:14px;display:inline-block;margin-left:6px;vertical-align:baseline;opacity:0.4;filter:alpha(opacity=40);font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f106"} +table.table.data thead th.sort-asc >a:after {font-size:14px;line-height:14px;display:inline-block;margin-left:6px;vertical-align:baseline;opacity:0.4;filter:alpha(opacity=40);font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f106"} table.table.data thead td.sort-asc >span:hover:after, table.table.data thead th.sort-asc >span:hover:after, table.table.data thead td.sort-asc >a:hover:after, @@ -4588,7 +4588,7 @@ table.table.data tr.list-tree-level-10 td.list-cell-index-1 {padding-left:115px} .control-list table.table.data {margin-bottom:0} .control-list table.table.data .list-setup {width:48px} .control-list table.table.data .list-setup a {display:block;color:#000} -.control-list table.table.data .list-setup a:before {font-size:14px;line-height:14px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f0ca";display:inline-block;margin-left:8px;vertical-align:baseline;opacity:0.6;filter:alpha(opacity=60)} +.control-list table.table.data .list-setup a:before {font-size:14px;line-height:14px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f0ca";display:inline-block;margin-left:8px;vertical-align:baseline;opacity:0.6;filter:alpha(opacity=60)} .control-list table.table.data .list-setup a:hover:before {opacity:1;filter:alpha(opacity=100);color:#4ea5e0 !important} .list-header {background-color:transparent;padding:0 20px 1px 20px} .list-header h3 {font-size:14px;color:#7e8c8d;text-transform:uppercase;font-weight:600;margin-top:0;margin-bottom:15px} @@ -4604,8 +4604,8 @@ table.table.data tr.list-tree-level-10 td.list-cell-index-1 {padding-left:115px} .list-scrollable-container {touch-action:auto;position:relative} .list-scrollable-container:after, .list-scrollable-container:before {display:none;position:absolute;top:50%;margin-top:-7px;height:9px;font-size:10px;color:#666} -.list-scrollable-container:before {left:-6px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f104"} -.list-scrollable-container:after {right:-8px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f105"} +.list-scrollable-container:before {left:-6px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f104"} +.list-scrollable-container:after {right:-8px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f105"} .list-scrollable-container.scroll-before:before {display:block} .list-scrollable-container.scroll-after:after {display:block} .list-scrollable-container:after, @@ -4668,8 +4668,8 @@ table.table.data tr.list-tree-level-10 td.list-cell-index-1 {padding-left:115px} .inspector-fields th >div >div span.info:hover {opacity:1;filter:alpha(opacity=100)} .inspector-fields th >div a.expandControl {display:block;position:absolute;width:12px;height:12px;left:-15px;top:2px;text-indent:-100000em} .inspector-fields th >div a.expandControl span {position:absolute;display:inline-block;left:0;top:0;width:12px;height:12px} -.inspector-fields th >div a.expandControl span:after {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f105";position:absolute;left:4px;top:-2px;width:12px;height:12px;font-size:13px;color:#333;text-indent:0} -.inspector-fields th >div a.expandControl.expanded span:after {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f107";left:2px} +.inspector-fields th >div a.expandControl span:after {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f105";position:absolute;left:4px;top:-2px;width:12px;height:12px;font-size:13px;color:#333;text-indent:0} +.inspector-fields th >div a.expandControl.expanded span:after {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f107";left:2px} .inspector-fields input[type=text] {display:block;width:100%;border:none;outline:none} .inspector-fields div.custom-checkbox {margin-top:0;margin-bottom:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none} .inspector-fields div.custom-checkbox label:before {top:-12px} @@ -4731,7 +4731,7 @@ ul.autocomplete.dropdown-menu.inspector-autocomplete li a {padding:5px 12px;whit .select2-dropdown.ocInspectorDropdown >.select2-results li >i, .select2-dropdown.ocInspectorDropdown >.select2-results li >img {margin-left:6px} .select2-dropdown.ocInspectorDropdown .select2-search {min-height:26px;position:relative;border-bottom:1px solid #b2b9be} -.select2-dropdown.ocInspectorDropdown .select2-search:after {position:absolute;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f002";right:10px;top:10px;color:#95a5a6} +.select2-dropdown.ocInspectorDropdown .select2-search:after {position:absolute;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f002";right:10px;top:10px;color:#95a5a6} .select2-dropdown.ocInspectorDropdown .select2-search input.select2-search__field {min-height:26px;background:transparent !important;font-size:13px;padding-left:4px;padding-right:20px;border:none} .control-pagination {font-size:0;text-align:center} @media (min-width:768px) {.control-pagination {text-align:right }} @@ -4763,17 +4763,17 @@ ul.autocomplete.dropdown-menu.inspector-autocomplete li a {padding:5px 12px;whit .control-pagination .page-back {padding-right:6px} .control-pagination .page-last {padding-left:6px} .control-pagination .page-first {padding-right:6px} -.control-pagination .page-next:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f105"} -.control-pagination .page-back:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f104"} -.control-pagination .page-last:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f101"} -.control-pagination .page-first:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f100"} +.control-pagination .page-next:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f105"} +.control-pagination .page-back:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f104"} +.control-pagination .page-last:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f101"} +.control-pagination .page-first:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f100"} .control-filter {padding:0 10px;color:rgba(0,0,0,0.6);background-color:#ecf0f1;border-top:1px solid #d7dbdd;border-bottom:1px solid #d7dbdd;font-size:13px} .control-filter .custom-checkbox label {font-size:13px;color:rgba(0,0,0,0.6)} .control-filter a {text-decoration:none;color:rgba(0,0,0,0.6)} .control-filter >.filter-scope {display:inline-block;padding:10px} .control-filter >.filter-scope .filter-label {margin-right:5px} .control-filter >.filter-scope .filter-setting {display:inline-block;margin-right:5px;-webkit-transition:color 0.6s;transition:color 0.6s} -.control-filter >.filter-scope:after {font-size:14px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f107"} +.control-filter >.filter-scope:after {font-size:14px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f107"} .control-filter >.filter-scope.active .filter-setting {padding-left:5px;padding-right:5px;color:#FFF;background-color:#6aab55;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-transition:color 1s,background-color 1s;transition:color 1s,background-color 1s} .control-filter >.filter-scope.checkbox {padding-left:35px} .control-filter >.filter-scope.checkbox, @@ -4796,7 +4796,7 @@ ul.autocomplete.dropdown-menu.inspector-autocomplete li a {padding:5px 12px;whit .control-filter >.filter-scope.active.active .filter-setting {background-color:#5f9a4c} .control-filter >.filter-has-popover {display:inline-block;padding:10px} .control-filter >.filter-has-popover .filter-setting {display:inline-block;-webkit-transition:color 0.6s;transition:color 0.6s} -.control-filter >.filter-has-popover:after {font-size:14px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f107"} +.control-filter >.filter-has-popover:after {font-size:14px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f107"} .control-filter >.filter-has-popover.active .filter-setting {padding-left:5px;padding-right:5px;color:#FFF;background-color:#6aab55;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-transition:color 1s,background-color 1s;transition:color 1s,background-color 1s} .control-filter >.filter-has-popover:hover {color:#000} .control-filter >.filter-has-popover:hover .filter-label {color:rgba(0,0,0,0.6)} @@ -4821,11 +4821,11 @@ ul.autocomplete.dropdown-menu.inspector-autocomplete li a {padding:5px 12px;whit .control-filter-popover .filter-items a:hover, .control-filter-popover .filter-active-items a:hover {background-color:#4da7e8;color:#FFF} .control-filter-popover .filter-items {max-height:135px;overflow:auto;background-color:#fafafa;border-bottom:1px solid #d7dbdd} -.control-filter-popover .filter-items a:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f067"} +.control-filter-popover .filter-items a:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f067"} .control-filter-popover .filter-items li.loading {padding:7px} .control-filter-popover .filter-items li.loading >span {display:block;height:20px;width:20px;background-image:url('images/loader-transparent.svg');background-size:20px 20px;background-position:50% 50%;-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite} .control-filter-popover .filter-items li.animate-enter {-webkit-animation:fadeInUp 0.5s;animation:fadeInUp 0.5s} -.control-filter-popover .filter-active-items a:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;content:"\f00d"} +.control-filter-popover .filter-active-items a:before {font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f00d"} .control-filter-popover .filter-active-items li.animate-enter {-webkit-animation:fadeInDown 0.5s;animation:fadeInDown 0.5s} .control-filter-popover.control-filter-box-popover {min-width:190px} .control-filter-popover.control-filter-box-popover .filter-buttons {margin:0;padding:0} From cae4070aebd3f091e4a18d2287087dddd1721853 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Wed, 11 Sep 2019 20:53:39 +1000 Subject: [PATCH 004/157] Peer review visibility changes It makes more sense to use a consistent UI for all modes, the CSS is cleaner as a result. The code editor toolbar has been moved to the bottom across all instances. This is favourable to it bleeding outside of its perimeter. Refs #3947 Refs #3948 --- .../codeeditor/assets/css/codeeditor.css | 13 ++-- .../codeeditor/assets/js/build-min.js | 2 +- .../codeeditor/assets/js/codeeditor.js | 14 ++-- .../codeeditor/assets/less/codeeditor.less | 69 ++++--------------- 4 files changed, 25 insertions(+), 73 deletions(-) diff --git a/modules/backend/formwidgets/codeeditor/assets/css/codeeditor.css b/modules/backend/formwidgets/codeeditor/assets/css/codeeditor.css index e40fbe2e91..097f0733e2 100644 --- a/modules/backend/formwidgets/codeeditor/assets/css/codeeditor.css +++ b/modules/backend/formwidgets/codeeditor/assets/css/codeeditor.css @@ -10,23 +10,18 @@ .field-codeeditor .ace_search .ace_search_form.ace_nomatch {outline:none !important} .field-codeeditor .ace_search .ace_search_form.ace_nomatch .ace_search_field {border:.0625rem solid red;-webkit-box-shadow:0 0 .1875rem .125rem red;box-shadow:0 0 .1875rem .125rem red;z-index:1;position:relative} .field-codeeditor .editor-code {-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px} -.field-codeeditor .editor-toolbar {position:absolute;top:-30px;right:35px;z-index:10} +.field-codeeditor .editor-toolbar {position:absolute;padding:0 5px;bottom:10px;right:25px;z-index:10;background:rgba(0,0,0,0.8);border-radius:5px} .field-codeeditor .editor-toolbar >ul, .field-codeeditor .editor-toolbar ul >li {list-style-type:none;padding:0;margin:0} .field-codeeditor .editor-toolbar >ul >li {float:left} .field-codeeditor .editor-toolbar >ul >li .tooltip.left {margin-right:25px} -.field-codeeditor .editor-toolbar >ul >li >a {display:block;height:25px;width:25px;color:#666;font-size:20px;text-align:center;text-decoration:none} +.field-codeeditor .editor-toolbar >ul >li >a {display:block;height:25px;width:25px;color:#666;font-size:20px;text-align:center;text-decoration:none;text-shadow:0 0 5px #000} .field-codeeditor .editor-toolbar >ul >li >a >abbr {position:absolute;font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0} .field-codeeditor .editor-toolbar >ul >li >a >i {opacity:1;filter:alpha(opacity=100);display:block} .field-codeeditor .editor-toolbar >ul >li >a >i:before {font-size:15px} .field-codeeditor .editor-toolbar >ul >li >a:hover >i, .field-codeeditor .editor-toolbar >ul >li >a:focus >i {opacity:1;filter:alpha(opacity=100);color:#fff} .field-codeeditor.editor-fullscreen {z-index:301;position:fixed !important;top:0;left:0;height:100%;border-width:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0} +.field-codeeditor.editor-fullscreen .editor-toolbar {z-index:302} .field-codeeditor.editor-fullscreen .editor-code {-webkit-border-radius:0;-moz-border-radius:0;border-radius:0} -.field-codeeditor.editor-fullscreen .editor-toolbar {z-index:302;border-radius:0 0 5px 5px;right:25px;background-color:#ddd;border:1px solid #cbcbcb;border-right-color:#cbcbcb;border-right-style:solid;border-right-width:1px;border-top:0 none;max-width:125px;overflow:hidden;margin:0;padding:4px;position:absolute;top:0;white-space:normal} -.field-codeeditor.editor-fullscreen .editor-toolbar >ul >li >a {color:#666} -.field-codeeditor.editor-fullscreen .editor-toolbar >ul >li >a:hover, -.field-codeeditor.editor-fullscreen .editor-toolbar >ul >li >a:focus {color:#191919} -.field-codeeditor.editor-fullscreen .ace_search {z-index:303} -.field-codeeditor .secondary-tabs .editor-toolbar >ul >li >a {color:#fff} -#cms-master-tabs .field-codeeditor .editor-toolbar >ul >li >a {color:#919898} \ No newline at end of file +.field-codeeditor.editor-fullscreen .ace_search {z-index:303} \ No newline at end of file diff --git a/modules/backend/formwidgets/codeeditor/assets/js/build-min.js b/modules/backend/formwidgets/codeeditor/assets/js/build-min.js index f7771f1a4a..d651f9765e 100644 --- a/modules/backend/formwidgets/codeeditor/assets/js/build-min.js +++ b/modules/backend/formwidgets/codeeditor/assets/js/build-min.js @@ -4586,7 +4586,7 @@ ace.require('ace/config').set('basePath',this.options.vendorPath) editor.setOptions({enableEmmet:options.enableEmmet,enableBasicAutocompletion:options.autocompletion==='basic',enableSnippets:options.enableSnippets,enableLiveAutocompletion:options.autocompletion==='live'}) editor.renderer.setScrollMargin(options.margin,options.margin,0,0) editor.renderer.setPadding(options.margin) -this.$toolbar.find('>ul>li>a').each(function(){var abbr=$(this).find('>abbr'),label=abbr.text(),help=abbr.attr('title'),title=label+' ('+help+')';$(this).attr('title',title)}).tooltip({delay:500,placement:'bottom',html:true});this.$fullscreenDisable.hide() +this.$toolbar.find('>ul>li>a').each(function(){var abbr=$(this).find('>abbr'),label=abbr.text(),help=abbr.attr('title'),title=label+' ('+help+')';$(this).attr('title',title)}).tooltip({delay:500,placement:'top',html:true});this.$fullscreenDisable.hide() this.$fullscreenEnable.on('click.codeeditor','>a',$.proxy(this.toggleFullscreen,this)) this.$fullscreenDisable.on('click.codeeditor','>a',$.proxy(this.toggleFullscreen,this)) this.$searchboxDisable.hide() diff --git a/modules/backend/formwidgets/codeeditor/assets/js/codeeditor.js b/modules/backend/formwidgets/codeeditor/assets/js/codeeditor.js index 337e5856a9..2d0ade840e 100644 --- a/modules/backend/formwidgets/codeeditor/assets/js/codeeditor.js +++ b/modules/backend/formwidgets/codeeditor/assets/js/codeeditor.js @@ -5,7 +5,7 @@ * - data-control="codeeditor" - enables the code editor plugin * - data-vendor-path="/" - sets the path to find Ace editor files * - data-language="php" - set the coding language used - * - data-theme="textmate" - the colour scheme and theme + * - data-theme="textmate" - the colour scheme and theme * * JavaScript API: * $('textarea').codeEditor({ vendorPath: '/', language: 'php '}) @@ -186,7 +186,7 @@ }) .tooltip({ delay: 500, - placement: 'bottom', + placement: 'top', html: true }) ; @@ -201,7 +201,7 @@ this.$replaceboxDisable.hide() this.$replaceboxEnable.on('click.codeeditor', '>a', $.proxy(this.toggleReplacebox, this)) - this.$replaceboxDisable.on('click.codeeditor', '>a', $.proxy(this.toggleReplacebox, this)) + this.$replaceboxDisable.on('click.codeeditor', '>a', $.proxy(this.toggleReplacebox, this)) /* * Hotkeys @@ -372,11 +372,11 @@ this.editor.resize() this.editor.focus() } - + CodeEditor.prototype.toggleSearchbox = function() { this.$searchboxEnable.toggle() this.$searchboxDisable.toggle() - + this.editor.execCommand("find") this.editor.resize() @@ -386,7 +386,7 @@ CodeEditor.prototype.toggleReplacebox = function() { this.$replaceboxEnable.toggle() this.$replaceboxDisable.toggle() - + this.editor.execCommand("replace") this.editor.resize() @@ -406,7 +406,7 @@ var options = $.extend({}, CodeEditor.DEFAULTS, $this.data(), typeof option == 'object' && option) if (!data) $this.data('oc.codeEditor', (data = new CodeEditor(this, options))) if (typeof option == 'string') result = data[option].apply(data, args) - if (typeof result != 'undefined') return false + if (typeof result != 'undefined') return false }) return result ? result : this diff --git a/modules/backend/formwidgets/codeeditor/assets/less/codeeditor.less b/modules/backend/formwidgets/codeeditor/assets/less/codeeditor.less index bdb0ff8b98..f216286392 100644 --- a/modules/backend/formwidgets/codeeditor/assets/less/codeeditor.less +++ b/modules/backend/formwidgets/codeeditor/assets/less/codeeditor.less @@ -1,12 +1,5 @@ @import "../../../../assets/less/core/boot.less"; -@color_1: #666; -@color_2: #fff; -@color_3: #919898; -@background_color_1: #ddd; -@border_right_color_1: #cbcbcb; -@fullscreen_icons_color_1: #191919; - .field-codeeditor { width: 100%; position: relative; @@ -28,6 +21,7 @@ color: @text-color; z-index: @zindex-form + 3; + // Fixes double focus on search box .ace_search_form.ace_nomatch { outline: none !important; @@ -47,9 +41,13 @@ .editor-toolbar { position: absolute; - top: -30px; - right: 35px; + padding: 0 5px; + bottom: 10px; + right: 25px; z-index: @zindex-form; + background: rgba(0,0,0,.8); + border-radius: 5px; + > ul, ul > li { list-style-type: none; padding: 0; margin: 0; } > ul > li { float: left; @@ -66,6 +64,8 @@ font-size: 20px; text-align: center; text-decoration: none; + text-shadow: 0 0 5px #000; + > abbr { position: absolute; .text-hide(); @@ -78,69 +78,26 @@ } } &:hover, &:focus { - > i { + > i { .opacity(1); - color: @color_2; + color: #fff; } } - } } &.editor-fullscreen { z-index: @zindex-fullscreen + 1; - position: fixed!important; + position: fixed !important; top: 0; left: 0; height: 100%; border-width: 0; .border-radius(0); - .editor-code { .border-radius(0); } .editor-toolbar { z-index: @zindex-fullscreen + 2; - border-radius: 0 0 5px 5px; - right: 25px; - background-color: @background_color_1; - border: 1px solid #cbcbcb; - border-right-color: @border_right_color_1; - border-right-style: solid; - border-right-width: 1px; - border-top: 0 none; - max-width: 125px; - overflow: hidden; - margin: 0; - padding: 4px; - position: absolute; - top: 0; - white-space: normal; - >ul { - >li { - >a { - color: @color_1; - &:hover, &:focus { - color: @fullscreen_icons_color_1; - } - } - } - } } + .editor-code { .border-radius(0); } .ace_search { z-index: @zindex-fullscreen + 3; } } - - .secondary-tabs { - .editor-toolbar { - >ul { - >li { - >a { - color: @color_2; - } - } - } - } - } - } - -#cms-master-tabs .field-codeeditor .editor-toolbar > ul > li > a { - color: @color_3; -} \ No newline at end of file From 849fbd700f3c7a5f07b0ad20249e144b23c817fe Mon Sep 17 00:00:00 2001 From: Ayumi Hamasaki <46076483+ayumihamasaki2@users.noreply.github.com> Date: Mon, 27 May 2019 16:52:08 +0100 Subject: [PATCH 005/157] Fixed the CSP Issue Have removed all the Data: elements and will now pass with a basic CSP Policy --- .../assets/ui/vendor/modernizr/modernizr.js | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/modules/system/assets/ui/vendor/modernizr/modernizr.js b/modules/system/assets/ui/vendor/modernizr/modernizr.js index 547aaf3971..f872101074 100644 --- a/modules/system/assets/ui/vendor/modernizr/modernizr.js +++ b/modules/system/assets/ui/vendor/modernizr/modernizr.js @@ -1,3 +1,25 @@ -/*! modernizr 3.6.0 (Custom Build) | MIT * - * https://modernizr.com/download/?-applicationcache-audio-backgroundsize-borderimage-borderradius-boxshadow-canvas-canvastext-cssanimations-csscolumns-cssgradients-cssreflections-csstransforms-csstransforms3d-csstransitions-flexbox-flexboxlegacy-fontface-forcetouch-generatedcontent-geolocation-hashchange-history-hsla-indexeddb-inlinesvg-input-inputtypes-localstorage-multiplebgs-opacity-postmessage-rgba-sessionstorage-smil-svg-svgclippaths-textshadow-touchevents-video-webgl-websockets-websqldatabase-webworkers-domprefixes-hasevent-mq-prefixes-setclasses-shiv-testallprops-testprop-teststyles !*/ -!function(e,t,n){function r(e,t){return typeof e===t}function o(){var e,t,n,o,a,i,s;for(var c in w)if(w.hasOwnProperty(c)){if(e=[],t=w[c],t.name&&(e.push(t.name.toLowerCase()),t.options&&t.options.aliases&&t.options.aliases.length))for(n=0;nf;f++)if(m=e[f],g=G.style[m],s(m,"-")&&(m=d(m)),G.style[m]!==n){if(a||r(o,"undefined"))return c(),"pfx"==t?m:!0;try{G.style[m]=o}catch(y){}if(G.style[m]!=g)return c(),"pfx"==t?m:!0}return c(),!1}function y(e,t,n,o,a){var i=e.charAt(0).toUpperCase()+e.slice(1),s=(e+" "+U.join(i+" ")+i).split(" ");return r(t,"string")||r(t,"undefined")?v(s,t,o,a):(s=(e+" "+O.join(i+" ")+i).split(" "),p(s,t,n))}function b(e,t,r){return y(e,n,n,t,r)}function T(e,t){var n=e.deleteDatabase(t);n.onsuccess=function(){u("indexeddb.deletedatabase",!0)},n.onerror=function(){u("indexeddb.deletedatabase",!1)}}var x=[],w=[],S={_version:"3.6.0",_config:{classPrefix:"",enableClasses:!0,enableJSClass:!0,usePrefixes:!0},_q:[],on:function(e,t){var n=this;setTimeout(function(){t(n[e])},0)},addTest:function(e,t,n){w.push({name:e,fn:t,options:n})},addAsyncTest:function(e){w.push({name:null,fn:e})}},Modernizr=function(){};Modernizr.prototype=S,Modernizr=new Modernizr,Modernizr.addTest("applicationcache","applicationCache"in e),Modernizr.addTest("geolocation","geolocation"in navigator),Modernizr.addTest("history",function(){var t=navigator.userAgent;return-1===t.indexOf("Android 2.")&&-1===t.indexOf("Android 4.0")||-1===t.indexOf("Mobile Safari")||-1!==t.indexOf("Chrome")||-1!==t.indexOf("Windows Phone")||"file:"===location.protocol?e.history&&"pushState"in e.history:!1}),Modernizr.addTest("postmessage","postMessage"in e),Modernizr.addTest("svg",!!t.createElementNS&&!!t.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect);var C=!1;try{C="WebSocket"in e&&2===e.WebSocket.CLOSING}catch(E){}Modernizr.addTest("websockets",C),Modernizr.addTest("localstorage",function(){var e="modernizr";try{return localStorage.setItem(e,e),localStorage.removeItem(e),!0}catch(t){return!1}}),Modernizr.addTest("sessionstorage",function(){var e="modernizr";try{return sessionStorage.setItem(e,e),sessionStorage.removeItem(e),!0}catch(t){return!1}}),Modernizr.addTest("websqldatabase","openDatabase"in e),Modernizr.addTest("webworkers","Worker"in e);var _=S._config.usePrefixes?" -webkit- -moz- -o- -ms- ".split(" "):["",""];S._prefixes=_;var k=t.documentElement,P="svg"===k.nodeName.toLowerCase();P||!function(e,t){function n(e,t){var n=e.createElement("p"),r=e.getElementsByTagName("head")[0]||e.documentElement;return n.innerHTML="x",r.insertBefore(n.lastChild,r.firstChild)}function r(){var e=b.elements;return"string"==typeof e?e.split(" "):e}function o(e,t){var n=b.elements;"string"!=typeof n&&(n=n.join(" ")),"string"!=typeof e&&(e=e.join(" ")),b.elements=n+" "+e,l(t)}function a(e){var t=y[e[h]];return t||(t={},v++,e[h]=v,y[v]=t),t}function i(e,n,r){if(n||(n=t),u)return n.createElement(e);r||(r=a(n));var o;return o=r.cache[e]?r.cache[e].cloneNode():g.test(e)?(r.cache[e]=r.createElem(e)).cloneNode():r.createElem(e),!o.canHaveChildren||m.test(e)||o.tagUrn?o:r.frag.appendChild(o)}function s(e,n){if(e||(e=t),u)return e.createDocumentFragment();n=n||a(e);for(var o=n.frag.cloneNode(),i=0,s=r(),c=s.length;c>i;i++)o.createElement(s[i]);return o}function c(e,t){t.cache||(t.cache={},t.createElem=e.createElement,t.createFrag=e.createDocumentFragment,t.frag=t.createFrag()),e.createElement=function(n){return b.shivMethods?i(n,e,t):t.createElem(n)},e.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+r().join().replace(/[\w\-:]+/g,function(e){return t.createElem(e),t.frag.createElement(e),'c("'+e+'")'})+");return n}")(b,t.frag)}function l(e){e||(e=t);var r=a(e);return!b.shivCSS||d||r.hasCSS||(r.hasCSS=!!n(e,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),u||c(e,r),e}var d,u,f="3.7.3",p=e.html5||{},m=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,g=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,h="_html5shiv",v=0,y={};!function(){try{var e=t.createElement("a");e.innerHTML="",d="hidden"in e,u=1==e.childNodes.length||function(){t.createElement("a");var e=t.createDocumentFragment();return"undefined"==typeof e.cloneNode||"undefined"==typeof e.createDocumentFragment||"undefined"==typeof e.createElement}()}catch(n){d=!0,u=!0}}();var b={elements:p.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:f,shivCSS:p.shivCSS!==!1,supportsUnknownElements:u,shivMethods:p.shivMethods!==!1,type:"default",shivDocument:l,createElement:i,createDocumentFragment:s,addElements:o};e.html5=b,l(t),"object"==typeof module&&module.exports&&(module.exports=b)}("undefined"!=typeof e?e:this,t);var N="Moz O ms Webkit",O=S._config.usePrefixes?N.toLowerCase().split(" "):[];S._domPrefixes=O;var z=function(){function e(e,t){var o;return e?(t&&"string"!=typeof t||(t=i(t||"div")),e="on"+e,o=e in t,!o&&r&&(t.setAttribute||(t=i("div")),t.setAttribute(e,""),o="function"==typeof t[e],t[e]!==n&&(t[e]=n),t.removeAttribute(e)),o):!1}var r=!("onblur"in t.documentElement);return e}();S.hasEvent=z,Modernizr.addTest("hashchange",function(){return z("hashchange",e)===!1?!1:t.documentMode===n||t.documentMode>7}),Modernizr.addTest("audio",function(){var e=i("audio"),t=!1;try{t=!!e.canPlayType,t&&(t=new Boolean(t),t.ogg=e.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),t.mp3=e.canPlayType('audio/mpeg; codecs="mp3"').replace(/^no$/,""),t.opus=e.canPlayType('audio/ogg; codecs="opus"')||e.canPlayType('audio/webm; codecs="opus"').replace(/^no$/,""),t.wav=e.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),t.m4a=(e.canPlayType("audio/x-m4a;")||e.canPlayType("audio/aac;")).replace(/^no$/,""))}catch(n){}return t}),Modernizr.addTest("canvas",function(){var e=i("canvas");return!(!e.getContext||!e.getContext("2d"))}),Modernizr.addTest("canvastext",function(){return Modernizr.canvas===!1?!1:"function"==typeof i("canvas").getContext("2d").fillText}),Modernizr.addTest("video",function(){var e=i("video"),t=!1;try{t=!!e.canPlayType,t&&(t=new Boolean(t),t.ogg=e.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),t.h264=e.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),t.webm=e.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,""),t.vp9=e.canPlayType('video/webm; codecs="vp9"').replace(/^no$/,""),t.hls=e.canPlayType('application/x-mpegURL; codecs="avc1.42E01E"').replace(/^no$/,""))}catch(n){}return t}),Modernizr.addTest("webgl",function(){var t=i("canvas"),n="probablySupportsContext"in t?"probablySupportsContext":"supportsContext";return n in t?t[n]("webgl")||t[n]("experimental-webgl"):"WebGLRenderingContext"in e}),Modernizr.addTest("cssgradients",function(){for(var e,t="background-image:",n="gradient(linear,left top,right bottom,from(#9f9),to(white));",r="",o=0,a=_.length-1;a>o;o++)e=0===o?"to ":"",r+=t+_[o]+"linear-gradient("+e+"left top, #9f9, white);";Modernizr._config.usePrefixes&&(r+=t+"-webkit-"+n);var s=i("a"),c=s.style;return c.cssText=r,(""+c.backgroundImage).indexOf("gradient")>-1}),Modernizr.addTest("multiplebgs",function(){var e=i("a").style;return e.cssText="background:url(https://),url(https://),red url(https://)",/(url\s*\(.*?){3}/.test(e.background)}),Modernizr.addTest("opacity",function(){var e=i("a").style;return e.cssText=_.join("opacity:.55;"),/^0.55$/.test(e.opacity)}),Modernizr.addTest("rgba",function(){var e=i("a").style;return e.cssText="background-color:rgba(150,255,150,.5)",(""+e.backgroundColor).indexOf("rgba")>-1}),Modernizr.addTest("inlinesvg",function(){var e=i("div");return e.innerHTML="","http://www.w3.org/2000/svg"==("undefined"!=typeof SVGRect&&e.firstChild&&e.firstChild.namespaceURI)});var R=i("input"),A="autocomplete autofocus list placeholder max min multiple pattern required step".split(" "),M={};Modernizr.input=function(t){for(var n=0,r=t.length;r>n;n++)M[t[n]]=!!(t[n]in R);return M.list&&(M.list=!(!i("datalist")||!e.HTMLDataListElement)),M}(A);var $="search tel url email datetime date month week time datetime-local number range color".split(" "),B={};Modernizr.inputtypes=function(e){for(var r,o,a,i=e.length,s="1)",c=0;i>c;c++)R.setAttribute("type",r=e[c]),a="text"!==R.type&&"style"in R,a&&(R.value=s,R.style.cssText="position:absolute;visibility:hidden;",/^range$/.test(r)&&R.style.WebkitAppearance!==n?(k.appendChild(R),o=t.defaultView,a=o.getComputedStyle&&"textfield"!==o.getComputedStyle(R,null).WebkitAppearance&&0!==R.offsetHeight,k.removeChild(R)):/^(search|tel)$/.test(r)||(a=/^(url|email)$/.test(r)?R.checkValidity&&R.checkValidity()===!1:R.value!=s)),B[e[c]]=!!a;return B}($),Modernizr.addTest("hsla",function(){var e=i("a").style;return e.cssText="background-color:hsla(120,40%,100%,.5)",s(e.backgroundColor,"rgba")||s(e.backgroundColor,"hsla")});var j="CSS"in e&&"supports"in e.CSS,L="supportsCSS"in e;Modernizr.addTest("supports",j||L);var D={}.toString;Modernizr.addTest("svgclippaths",function(){return!!t.createElementNS&&/SVGClipPath/.test(D.call(t.createElementNS("http://www.w3.org/2000/svg","clipPath")))}),Modernizr.addTest("smil",function(){return!!t.createElementNS&&/SVGAnimate/.test(D.call(t.createElementNS("http://www.w3.org/2000/svg","animate")))});var F=function(){var t=e.matchMedia||e.msMatchMedia;return t?function(e){var n=t(e);return n&&n.matches||!1}:function(t){var n=!1;return l("@media "+t+" { #modernizr { position: absolute; } }",function(t){n="absolute"==(e.getComputedStyle?e.getComputedStyle(t,null):t.currentStyle).position}),n}}();S.mq=F;var I=S.testStyles=l,W=function(){var e=navigator.userAgent,t=e.match(/w(eb)?osbrowser/gi),n=e.match(/windows phone/gi)&&e.match(/iemobile\/([0-9])+/gi)&&parseFloat(RegExp.$1)>=9;return t||n}();W?Modernizr.addTest("fontface",!1):I('@font-face {font-family:"font";src:url("https://")}',function(e,n){var r=t.getElementById("smodernizr"),o=r.sheet||r.styleSheet,a=o?o.cssRules&&o.cssRules[0]?o.cssRules[0].cssText:o.cssText||"":"",i=/src/i.test(a)&&0===a.indexOf(n.split(" ")[0]);Modernizr.addTest("fontface",i)}),I('#modernizr{font:0/0 a}#modernizr:after{content:":)";visibility:hidden;font:7px/1 a}',function(e){Modernizr.addTest("generatedcontent",e.offsetHeight>=6)}),Modernizr.addTest("touchevents",function(){var n;if("ontouchstart"in e||e.DocumentTouch&&t instanceof DocumentTouch)n=!0;else{var r=["@media (",_.join("touch-enabled),("),"heartz",")","{#modernizr{top:9px;position:absolute}}"].join("");I(r,function(e){n=9===e.offsetTop})}return n});var U=S._config.usePrefixes?N.split(" "):[];S._cssomPrefixes=U;var V=function(t){var r,o=_.length,a=e.CSSRule;if("undefined"==typeof a)return n;if(!t)return!1;if(t=t.replace(/^@/,""),r=t.replace(/-/g,"_").toUpperCase()+"_RULE",r in a)return"@"+t;for(var i=0;o>i;i++){var s=_[i],c=s.toUpperCase()+"_"+r;if(c in a)return"@-"+s.toLowerCase()+"-"+t}return!1};S.atRule=V;var q;!function(){var e={}.hasOwnProperty;q=r(e,"undefined")||r(e.call,"undefined")?function(e,t){return t in e&&r(e.constructor.prototype[t],"undefined")}:function(t,n){return e.call(t,n)}}(),S._l={},S.on=function(e,t){this._l[e]||(this._l[e]=[]),this._l[e].push(t),Modernizr.hasOwnProperty(e)&&setTimeout(function(){Modernizr._trigger(e,Modernizr[e])},0)},S._trigger=function(e,t){if(this._l[e]){var n=this._l[e];setTimeout(function(){var e,r;for(e=0;e` element. This + * information allows you to progressively enhance your pages with a granular level + * of control over the experience. +*/ +!function(f,u,p){var s=[],e={_version:"3.7.1",_config:{classPrefix:"",enableClasses:!0,enableJSClass:!0,usePrefixes:!0},_q:[],on:function(e,t){var n=this;setTimeout(function(){t(n[e])},0)},addTest:function(e,t,n){s.push({name:e,fn:t,options:n})},addAsyncTest:function(e){s.push({name:null,fn:e})}},c=function(){};c.prototype=e,c=new c;var d=[];function m(e,t){return typeof e===t}var h=u.documentElement,g="svg"===h.nodeName.toLowerCase();function a(e){var t=h.className,n=c._config.classPrefix||"";if(g&&(t=t.baseVal),c._config.enableJSClass){var r=new RegExp("(^|\\s)"+n+"no-js(\\s|$)");t=t.replace(r,"$1"+n+"js$2")}c._config.enableClasses&&(0",r.insertBefore(n.lastChild,r.firstChild)}function f(){var e=h.elements;return"string"==typeof e?e.split(" "):e}function p(e){var t=c[e[r]];return t||(t={},d++,e[r]=d,c[d]=t),t}function l(e,t,n){return t||(t=i),s?t.createElement(e):(n||(n=p(t)),!(r=n.cache[e]?n.cache[e].cloneNode():a.test(e)?(n.cache[e]=n.createElem(e)).cloneNode():n.createElem(e)).canHaveChildren||o.test(e)||r.tagUrn?r:n.frag.appendChild(r));var r}function m(e){e||(e=i);var t=p(e);return!h.shivCSS||n||t.hasCSS||(t.hasCSS=!!u(e,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),s||function(t,n){n.cache||(n.cache={},n.createElem=t.createElement,n.createFrag=t.createDocumentFragment,n.frag=n.createFrag()),t.createElement=function(e){return h.shivMethods?l(e,t,n):n.createElem(e)},t.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+f().join().replace(/[\w\-:]+/g,function(e){return n.createElem(e),n.frag.createElement(e),'c("'+e+'")'})+");return n}")(h,n.frag)}(e,t),e}!function(){try{var e=i.createElement("a");e.innerHTML="",n="hidden"in e,s=1==e.childNodes.length||function(){i.createElement("a");var e=i.createDocumentFragment();return void 0===e.cloneNode||void 0===e.createDocumentFragment||void 0===e.createElement}()}catch(e){s=n=!0}}();var h={elements:t.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:"3.7.3",shivCSS:!1!==t.shivCSS,supportsUnknownElements:s,shivMethods:!1!==t.shivMethods,type:"default",shivDocument:m,createElement:l,createDocumentFragment:function(e,t){if(e||(e=i),s)return e.createDocumentFragment();for(var n=(t=t||p(e)).frag.cloneNode(),r=0,o=f(),a=o.length;r+~])("+f().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),a="$1"+y+"\\:$2";r--;)(t=n[r]=n[r].split("}"))[t.length-1]=t[t.length-1].replace(o,a),n[r]=t.join("}");return n.join("{")}(o.reverse().join("")),c=function(e){for(var t,n=e.getElementsByTagName("*"),r=n.length,o=RegExp("^(?:"+f().join("|")+")$","i"),a=[];r--;)t=n[r],o.test(t.nodeName)&&a.push(t.applyElement(T(t)));return a}(s),d=u(s,o)}),n.attachEvent("onafterprint",function(){!function(e){for(var t=e.length;t--;)e[t].removeNode()}(c),clearTimeout(e._removeSheetTimer),e._removeSheetTimer=setTimeout(l,500)}),s.printShived=!0,s}h.type+=" print",(h.shivPrint=x)(i),"object"==typeof module&&module.exports&&(module.exports=h)}(void 0!==f?f:this,u);var T=e._config.usePrefixes?t.split(" "):[];function x(e,t){return!!~(""+e).indexOf(t)}e._cssomPrefixes=T;var w={elem:v("modernizr")};c._q.push(function(){delete w.elem});var S={style:w.elem.style};function C(e){return e.replace(/([A-Z])/g,function(e,t){return"-"+t.toLowerCase()}).replace(/^ms-/,"-ms-")}function E(e,t,n){var r;if("getComputedStyle"in f){r=getComputedStyle.call(f,e,t);var o=f.console;if(null!==r)n&&(r=r.getPropertyValue(n));else if(o)o[o.error?"error":"log"].call(o,"getComputedStyle returning null, its possible modernizr test results are inaccurate")}else r=!t&&e.currentStyle&&e.currentStyle[n];return r}function k(e){return e.replace(/([a-z])-([a-z])/g,function(e,t,n){return t+n.toUpperCase()}).replace(/^-/,"")}function _(e,t,n,r){if(r=!m(r,"undefined")&&r,!m(n,"undefined")){var o=function(e,t){var n=e.length;if("CSS"in f&&"supports"in f.CSS){for(;n--;)if(f.CSS.supports(C(e[n]),t))return!0;return!1}if("CSSSupportsRule"in f){for(var r=[];n--;)r.push("("+C(e[n])+":"+t+")");return y("@supports ("+(r=r.join(" or "))+") { #modernizr { position: absolute; } }",function(e){return"absolute"===E(e,null,"position")})}return p}(e,n);if(!m(o,"undefined"))return o}for(var a,i,s,d,c,l=["modernizr","tspan","samp"];!S.style&&l.length;)a=!0,S.modElem=v(l.shift()),S.style=S.modElem.style;function u(){a&&(delete S.style,delete S.modElem)}for(s=e.length,i=0;i Date: Mon, 27 May 2019 17:12:52 +0100 Subject: [PATCH 006/157] Remove the extra head info Remove these extra lines of code - not needed --- .../assets/ui/vendor/modernizr/modernizr.js | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/modules/system/assets/ui/vendor/modernizr/modernizr.js b/modules/system/assets/ui/vendor/modernizr/modernizr.js index f872101074..60edf6d9d9 100644 --- a/modules/system/assets/ui/vendor/modernizr/modernizr.js +++ b/modules/system/assets/ui/vendor/modernizr/modernizr.js @@ -1,25 +1,5 @@ /*! * modernizr v3.7.1 * Build https://modernizr.com/download?-applicationcache-audio-audioloop-backgroundsize-bgsizecover-borderimage-borderradius-boxshadow-boxsizing-canvas-canvastext-cssanimations-csscalc-csscolumns-cssgradients-cssgrid_cssgridlegacy-cssreflections-csstransforms-csstransforms3d-csstransformslevel2-csstransitions-cssvhunit-cssvmaxunit-cssvminunit-cssvwunit-flexbox-flexboxlegacy-flexboxtweener-flexwrap-fontdisplay-fontface-forcetouch-generatedcontent-geolocation-hashchange-history-hsla-indexeddb-indexeddbblob-inlinesvg-input-inputformaction-inputformenctype-inputformmethod-inputformnovalidate-inputformtarget-inputsearchevent-inputtypes-localstorage-multiplebgs-opacity-postmessage-preserve3d-rgba-sessionstorage-smil-srcset-svg-svgasimg-svgclippaths-svgfilters-svgforeignobject-textshadow-touchevents-video-videocrossorigin-videoloop-videopreload-webaudio-webgl-webglextensions-websockets-websocketsbinary-websqldatabase-webworkers-domprefixes-hasevent-mq-prefixes-printshiv-setclasses-testallprops-testprop-teststyles-dontmin - * - * Copyright (c) - * Faruk Ates - * Paul Irish - * Alex Sexton - * Ryan Seddon - * Patrick Kettner - * Stu Cox - * Richard Herrera - * Veeck - - * MIT License - */ - -/* - * Modernizr tests which native CSS3 and HTML5 features are available in the - * current UA and makes the results available to you in two ways: as properties on - * a global `Modernizr` object, and as classes on the `` element. This - * information allows you to progressively enhance your pages with a granular level - * of control over the experience. */ !function(f,u,p){var s=[],e={_version:"3.7.1",_config:{classPrefix:"",enableClasses:!0,enableJSClass:!0,usePrefixes:!0},_q:[],on:function(e,t){var n=this;setTimeout(function(){t(n[e])},0)},addTest:function(e,t,n){s.push({name:e,fn:t,options:n})},addAsyncTest:function(e){s.push({name:null,fn:e})}},c=function(){};c.prototype=e,c=new c;var d=[];function m(e,t){return typeof e===t}var h=u.documentElement,g="svg"===h.nodeName.toLowerCase();function a(e){var t=h.className,n=c._config.classPrefix||"";if(g&&(t=t.baseVal),c._config.enableJSClass){var r=new RegExp("(^|\\s)"+n+"no-js(\\s|$)");t=t.replace(r,"$1"+n+"js$2")}c._config.enableClasses&&(0",r.insertBefore(n.lastChild,r.firstChild)}function f(){var e=h.elements;return"string"==typeof e?e.split(" "):e}function p(e){var t=c[e[r]];return t||(t={},d++,e[r]=d,c[d]=t),t}function l(e,t,n){return t||(t=i),s?t.createElement(e):(n||(n=p(t)),!(r=n.cache[e]?n.cache[e].cloneNode():a.test(e)?(n.cache[e]=n.createElem(e)).cloneNode():n.createElem(e)).canHaveChildren||o.test(e)||r.tagUrn?r:n.frag.appendChild(r));var r}function m(e){e||(e=i);var t=p(e);return!h.shivCSS||n||t.hasCSS||(t.hasCSS=!!u(e,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),s||function(t,n){n.cache||(n.cache={},n.createElem=t.createElement,n.createFrag=t.createDocumentFragment,n.frag=n.createFrag()),t.createElement=function(e){return h.shivMethods?l(e,t,n):n.createElem(e)},t.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+f().join().replace(/[\w\-:]+/g,function(e){return n.createElem(e),n.frag.createElement(e),'c("'+e+'")'})+");return n}")(h,n.frag)}(e,t),e}!function(){try{var e=i.createElement("a");e.innerHTML="",n="hidden"in e,s=1==e.childNodes.length||function(){i.createElement("a");var e=i.createDocumentFragment();return void 0===e.cloneNode||void 0===e.createDocumentFragment||void 0===e.createElement}()}catch(e){s=n=!0}}();var h={elements:t.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:"3.7.3",shivCSS:!1!==t.shivCSS,supportsUnknownElements:s,shivMethods:!1!==t.shivMethods,type:"default",shivDocument:m,createElement:l,createDocumentFragment:function(e,t){if(e||(e=i),s)return e.createDocumentFragment();for(var n=(t=t||p(e)).frag.cloneNode(),r=0,o=f(),a=o.length;r+~])("+f().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),a="$1"+y+"\\:$2";r--;)(t=n[r]=n[r].split("}"))[t.length-1]=t[t.length-1].replace(o,a),n[r]=t.join("}");return n.join("{")}(o.reverse().join("")),c=function(e){for(var t,n=e.getElementsByTagName("*"),r=n.length,o=RegExp("^(?:"+f().join("|")+")$","i"),a=[];r--;)t=n[r],o.test(t.nodeName)&&a.push(t.applyElement(T(t)));return a}(s),d=u(s,o)}),n.attachEvent("onafterprint",function(){!function(e){for(var t=e.length;t--;)e[t].removeNode()}(c),clearTimeout(e._removeSheetTimer),e._removeSheetTimer=setTimeout(l,500)}),s.printShived=!0,s}h.type+=" print",(h.shivPrint=x)(i),"object"==typeof module&&module.exports&&(module.exports=h)}(void 0!==f?f:this,u);var T=e._config.usePrefixes?t.split(" "):[];function x(e,t){return!!~(""+e).indexOf(t)}e._cssomPrefixes=T;var w={elem:v("modernizr")};c._q.push(function(){delete w.elem});var S={style:w.elem.style};function C(e){return e.replace(/([A-Z])/g,function(e,t){return"-"+t.toLowerCase()}).replace(/^ms-/,"-ms-")}function E(e,t,n){var r;if("getComputedStyle"in f){r=getComputedStyle.call(f,e,t);var o=f.console;if(null!==r)n&&(r=r.getPropertyValue(n));else if(o)o[o.error?"error":"log"].call(o,"getComputedStyle returning null, its possible modernizr test results are inaccurate")}else r=!t&&e.currentStyle&&e.currentStyle[n];return r}function k(e){return e.replace(/([a-z])-([a-z])/g,function(e,t,n){return t+n.toUpperCase()}).replace(/^-/,"")}function _(e,t,n,r){if(r=!m(r,"undefined")&&r,!m(n,"undefined")){var o=function(e,t){var n=e.length;if("CSS"in f&&"supports"in f.CSS){for(;n--;)if(f.CSS.supports(C(e[n]),t))return!0;return!1}if("CSSSupportsRule"in f){for(var r=[];n--;)r.push("("+C(e[n])+":"+t+")");return y("@supports ("+(r=r.join(" or "))+") { #modernizr { position: absolute; } }",function(e){return"absolute"===E(e,null,"position")})}return p}(e,n);if(!m(o,"undefined"))return o}for(var a,i,s,d,c,l=["modernizr","tspan","samp"];!S.style&&l.length;)a=!0,S.modElem=v(l.shift()),S.style=S.modElem.style;function u(){a&&(delete S.style,delete S.modElem)}for(s=e.length,i=0;i Date: Wed, 11 Sep 2019 21:35:18 +1000 Subject: [PATCH 007/157] Update Deprecated code in October into (event.key) (#4489) Update Deprecated code in October into (event.key) --- modules/backend/assets/js/october.flyout.js | 2 +- .../richeditor/assets/js/plugins/figures.js | 34 +++++++------------ .../assets/js/mediamanager-browser-min.js | 6 ++-- .../mediamanager/assets/js/mediamanager.js | 14 ++++---- .../widgets/table/assets/js/build-min.js | 32 ++++++++--------- .../assets/js/table.helper.navigation.js | 10 +++--- .../table/assets/js/table.helper.search.js | 2 +- .../backend/widgets/table/assets/js/table.js | 4 +-- .../assets/js/table.processor.checkbox.js | 2 +- .../assets/js/table.processor.dropdown.js | 18 +++++----- modules/system/assets/js/framework-min.js | 2 +- .../assets/js/framework.combined-min.js | 2 +- modules/system/assets/js/framework.js | 2 +- modules/system/assets/ui/js/autocomplete.js | 14 ++++---- modules/system/assets/ui/js/checkbox.js | 4 +-- modules/system/assets/ui/js/input.hotkey.js | 10 +++--- .../ui/js/inspector.editor.dictionary.js | 4 +-- ...inspector.editor.stringlistautocomplete.js | 4 +-- .../assets/ui/js/inspector.wrapper.popup.js | 2 +- modules/system/assets/ui/js/popover.js | 2 +- modules/system/assets/ui/js/tab.js | 2 +- 21 files changed, 83 insertions(+), 89 deletions(-) diff --git a/modules/backend/assets/js/october.flyout.js b/modules/backend/assets/js/october.flyout.js index 2f49925726..1d5c9b15ae 100644 --- a/modules/backend/assets/js/october.flyout.js +++ b/modules/backend/assets/js/october.flyout.js @@ -172,7 +172,7 @@ } Flyout.prototype.onDocumentKeydown = function(ev) { - if (ev.which == 27) { + if (ev.key === 'Escape') { this.hide(); } } diff --git a/modules/backend/formwidgets/richeditor/assets/js/plugins/figures.js b/modules/backend/formwidgets/richeditor/assets/js/plugins/figures.js index a82ca02e2a..fed8db5bc5 100644 --- a/modules/backend/formwidgets/richeditor/assets/js/plugins/figures.js +++ b/modules/backend/formwidgets/richeditor/assets/js/plugins/figures.js @@ -85,28 +85,24 @@ } function _handleUiBlocksKeydown(ev) { - if (ev.which == 40 || ev.which == 38 || ev.which == 8 || ev.which == 46) { + if (ev.key === 'ArrowDown' || ev.key === 'ArrowUp' || ev.key === 'Backspace' || ev.key === 'Delete') { var $block = $(editor.selection.element()) if ($block.is('br')) { $block = $block.parent() } if (!!$block.length) { - switch (ev.which) { - case 38: - // Up arrow + switch (ev.key) { + case 'ArrowUp': _handleUiBlockCaretIn($block.prev()) break - case 40: - // Down arrow + case 'ArrowDown': _handleUiBlockCaretIn($block.next()) break - case 46: - // Delete key + case 'Delete': _handleUiBlockCaretClearEmpty($block.next(), $block) break - case 8: - // Backspace key + case 'Backspace': _handleUiBlockCaretClearEmpty($block.prev(), $block) break } @@ -133,27 +129,23 @@ } function _uiBlockKeyDown(ev, block) { - if (ev.which == 40 || ev.which == 38 || ev.which == 13 || ev.which == 8 || ev.which == 46) { - switch (ev.which) { - case 40: - // Down arrow + if (ev.key === 'ArrowDown' || ev.key === 'ArrowUp' || ev.key === 'Enter' || ev.key === 'Backspace' || ev.key === 'Delete') { + switch (ev.key) { + case 'ArrowDown': _focusUiBlockOrText($(block).next(), true) break - case 38: - // Up arrow + case 'ArrowUp': _focusUiBlockOrText($(block).prev(), false) break - case 13: - // Enter key + case 'Enter': var $paragraph = $('


') $paragraph.insertAfter(block) editor.selection.setAfter(block) editor.selection.restore() editor.undo.saveStep() break - case 8: - case 46: - // Delete / Backspace key + case 'Backspace': + case 'Delete': var $nextFocus = $(block).next(), gotoStart = true diff --git a/modules/backend/widgets/mediamanager/assets/js/mediamanager-browser-min.js b/modules/backend/widgets/mediamanager/assets/js/mediamanager-browser-min.js index 0d9d535f36..6d2631a70d 100644 --- a/modules/backend/widgets/mediamanager/assets/js/mediamanager-browser-min.js +++ b/modules/backend/widgets/mediamanager/assets/js/mediamanager-browser-min.js @@ -454,13 +454,13 @@ MediaManager.prototype.onSortingChanged=function(ev){var $target=$(ev.target),da if($target.data('sort')=='by'){data.sortBy=$target.val();}else if($target.data('sort')=='direction'){data.sortDirection=$target.val()} this.execNavigationRequest('onSetSorting',data)} MediaManager.prototype.onKeyDown=function(ev){var eventHandled=false -switch(ev.which){case 13:var items=this.getSelectedItems(true,true) +switch(ev.key){case 'Enter':var items=this.getSelectedItems(true,true) if(items.length>0) this.navigateToItem($(items[0])) eventHandled=true -break;case 39:case 40:this.selectRelative(true,ev.shiftKey) +break;case 'ArrowRight':case 'ArrowDown':this.selectRelative(true,ev.shiftKey) eventHandled=true -break;case 37:case 38:this.selectRelative(false,ev.shiftKey) +break;case 'ArrowLeft':case 'ArrowUp':this.selectRelative(false,ev.shiftKey) eventHandled=true break;} if(eventHandled){ev.preventDefault() diff --git a/modules/backend/widgets/mediamanager/assets/js/mediamanager.js b/modules/backend/widgets/mediamanager/assets/js/mediamanager.js index f0b5510108..4d46f6b382 100644 --- a/modules/backend/widgets/mediamanager/assets/js/mediamanager.js +++ b/modules/backend/widgets/mediamanager/assets/js/mediamanager.js @@ -1025,6 +1025,7 @@ var item = items[i], path = item.getAttribute('data-path') + if (item.getAttribute('data-item-type') == 'folder') data.folders.push(path) else @@ -1250,21 +1251,22 @@ MediaManager.prototype.onKeyDown = function(ev) { var eventHandled = false - switch (ev.which) { - case 13: + + switch (ev.key) { + case 'Enter': var items = this.getSelectedItems(true, true) if (items.length > 0) this.navigateToItem($(items[0])) eventHandled = true break; - case 39: - case 40: + case 'ArrowRight': + case 'ArrowDown': this.selectRelative(true, ev.shiftKey) eventHandled = true break; - case 37: - case 38: + case 'ArrowLeft': + case 'ArrowUp': this.selectRelative(false, ev.shiftKey) eventHandled = true break; diff --git a/modules/backend/widgets/table/assets/js/build-min.js b/modules/backend/widgets/table/assets/js/build-min.js index ec262147f7..9717d65ec8 100644 --- a/modules/backend/widgets/table/assets/js/build-min.js +++ b/modules/backend/widgets/table/assets/js/build-min.js @@ -269,11 +269,11 @@ var target=this.getEventTarget(ev,'TD') if(!target){this.unfocusTable();return;} if(target.tagName!='TD'){this.unfocusTable();return;} this.focusCell(target,true)} -Table.prototype.onKeydown=function(ev){if(ev.keyCode==65&&ev.altKey&&this.options.adding){if(!ev.shiftKey){this.addRecord('below')} +Table.prototype.onKeydown=function(ev){if((ev.key==='a'||ev.key==='A')&&ev.altKey&&this.options.adding){if(!ev.shiftKey){this.addRecord('below')} else{this.addRecord('above')} this.stopEvent(ev) return} -if(ev.keyCode==68&&ev.altKey&&this.options.deleting){this.deleteRecord() +if((ev.key==='d'||ev.key==='D')&&ev.altKey&&this.options.deleting){this.deleteRecord() this.stopEvent(ev) return} for(var i=0,len=this.options.columns.length;i Date: Wed, 11 Sep 2019 21:42:02 +1000 Subject: [PATCH 008/157] Fixes typo, recompile assets --- .../richeditor/assets/js/build-plugins-min.js | 18 +++++------ .../assets/js/mediamanager-browser-min.js | 6 ++-- .../widgets/table/assets/js/build-min.js | 2 +- modules/system/assets/ui/js/checkbox.js | 4 +-- modules/system/assets/ui/storm-min.js | 30 +++++++++---------- 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/modules/backend/formwidgets/richeditor/assets/js/build-plugins-min.js b/modules/backend/formwidgets/richeditor/assets/js/build-plugins-min.js index 7e6d7bc742..905027eb68 100644 --- a/modules/backend/formwidgets/richeditor/assets/js/build-plugins-min.js +++ b/modules/backend/formwidgets/richeditor/assets/js/build-plugins-min.js @@ -93,15 +93,15 @@ $node.attr('data-label',text) insertElement($node)} function _initUiBlocks(){$('[data-video], [data-audio]',editor.$el).each(function(){$(this).addClass('fr-draggable').attr({'data-ui-block':'true','draggable':'true','tabindex':'0'}).html(' ') this.contentEditable=false})} -function _handleUiBlocksKeydown(ev){if(ev.which==40||ev.which==38||ev.which==8||ev.which==46){var $block=$(editor.selection.element()) +function _handleUiBlocksKeydown(ev){if(ev.key==='ArrowDown'||ev.key==='ArrowUp'||ev.key==='Backspace'||ev.key==='Delete'){var $block=$(editor.selection.element()) if($block.is('br')){$block=$block.parent()} -if(!!$block.length){switch(ev.which){case 38:_handleUiBlockCaretIn($block.prev()) +if(!!$block.length){switch(ev.key){case'ArrowUp':_handleUiBlockCaretIn($block.prev()) break -case 40:_handleUiBlockCaretIn($block.next()) +case'ArrowDown':_handleUiBlockCaretIn($block.next()) break -case 46:_handleUiBlockCaretClearEmpty($block.next(),$block) +case'Delete':_handleUiBlockCaretClearEmpty($block.next(),$block) break -case 8:_handleUiBlockCaretClearEmpty($block.prev(),$block) +case'Backspace':_handleUiBlockCaretClearEmpty($block.prev(),$block) break}}}} function _handleUiBlockCaretClearEmpty($block,$p){if($block.attr('data-ui-block')!==undefined&&$.trim($p.text()).length==0){$p.remove() _handleUiBlockCaretIn($block) @@ -110,17 +110,17 @@ function _handleUiBlockCaretIn($block){if($block.attr('data-ui-block')!==undefin editor.selection.clear() return true} return false} -function _uiBlockKeyDown(ev,block){if(ev.which==40||ev.which==38||ev.which==13||ev.which==8||ev.which==46){switch(ev.which){case 40:_focusUiBlockOrText($(block).next(),true) +function _uiBlockKeyDown(ev,block){if(ev.key==='ArrowDown'||ev.key==='ArrowUp'||ev.key==='Enter'||ev.key==='Backspace'||ev.key==='Delete'){switch(ev.key){case'ArrowDown':_focusUiBlockOrText($(block).next(),true) break -case 38:_focusUiBlockOrText($(block).prev(),false) +case'ArrowUp':_focusUiBlockOrText($(block).prev(),false) break -case 13:var $paragraph=$('


') +case'Enter':var $paragraph=$('


') $paragraph.insertAfter(block) editor.selection.setAfter(block) editor.selection.restore() editor.undo.saveStep() break -case 8:case 46:var $nextFocus=$(block).next(),gotoStart=true +case'Backspace':case'Delete':var $nextFocus=$(block).next(),gotoStart=true if($nextFocus.length==0){$nextFocus=$(block).prev() gotoStart=false} _focusUiBlockOrText($nextFocus,gotoStart) diff --git a/modules/backend/widgets/mediamanager/assets/js/mediamanager-browser-min.js b/modules/backend/widgets/mediamanager/assets/js/mediamanager-browser-min.js index 6d2631a70d..bf718d14a2 100644 --- a/modules/backend/widgets/mediamanager/assets/js/mediamanager-browser-min.js +++ b/modules/backend/widgets/mediamanager/assets/js/mediamanager-browser-min.js @@ -454,13 +454,13 @@ MediaManager.prototype.onSortingChanged=function(ev){var $target=$(ev.target),da if($target.data('sort')=='by'){data.sortBy=$target.val();}else if($target.data('sort')=='direction'){data.sortDirection=$target.val()} this.execNavigationRequest('onSetSorting',data)} MediaManager.prototype.onKeyDown=function(ev){var eventHandled=false -switch(ev.key){case 'Enter':var items=this.getSelectedItems(true,true) +switch(ev.key){case'Enter':var items=this.getSelectedItems(true,true) if(items.length>0) this.navigateToItem($(items[0])) eventHandled=true -break;case 'ArrowRight':case 'ArrowDown':this.selectRelative(true,ev.shiftKey) +break;case'ArrowRight':case'ArrowDown':this.selectRelative(true,ev.shiftKey) eventHandled=true -break;case 'ArrowLeft':case 'ArrowUp':this.selectRelative(false,ev.shiftKey) +break;case'ArrowLeft':case'ArrowUp':this.selectRelative(false,ev.shiftKey) eventHandled=true break;} if(eventHandled){ev.preventDefault() diff --git a/modules/backend/widgets/table/assets/js/build-min.js b/modules/backend/widgets/table/assets/js/build-min.js index 9717d65ec8..7bac16e129 100644 --- a/modules/backend/widgets/table/assets/js/build-min.js +++ b/modules/backend/widgets/table/assets/js/build-min.js @@ -909,7 +909,7 @@ var target=this.tableObj.getEventTarget(ev) if(target.tagName=='LI'){target.focus();}} DropdownProcessor.prototype.onKeyDown=function(ev){if(!this.itemListElement) return -if((ev.key==='(Space character)'||ev.key==='Spacebar'||ev.key===' ')&&!this.searching){this.showDropdown()}else if(ev.key==='ArrowDown'||ev.key==='ArrowUp'){var selected=this.findSelectedItem(),newSelectedItem;if(!selected){if(ev.key=='ArrowUp'){return false} +if((ev.key==='(Space character)'||ev.key==='Spacebar'||ev.key===' ')&&!this.searching){this.showDropdown()}else if(ev.key==='ArrowDown'||ev.key==='ArrowUp'){var selected=this.findSelectedItem(),newSelectedItem;if(!selected){if(ev.key==='ArrowUp'){return false} newSelectedItem=this.itemListElement.querySelector('ul li:first-child')}else{newSelectedItem=selected.nextElementSibling if(ev.key==='ArrowUp') newSelectedItem=selected.previousElementSibling} diff --git a/modules/system/assets/ui/js/checkbox.js b/modules/system/assets/ui/js/checkbox.js index 7549fda368..1f6a6a14d6 100644 --- a/modules/system/assets/ui/js/checkbox.js +++ b/modules/system/assets/ui/js/checkbox.js @@ -11,7 +11,7 @@ }) $(document).on('input', 'div.custom-checkbox', function(e) { - if (e.key === '(Space character)' || e.key === 'Spacebar' || e.key === ' ') + if (e.key === '(Space character)' || e.key === 'Spacebar' || e.key === ' ') { var $cb = $('input', this) if ($cb.data('oc-space-timestamp') == e.timeStamp) @@ -88,4 +88,4 @@ return false }) -})(jQuery); \ No newline at end of file +})(jQuery); diff --git a/modules/system/assets/ui/storm-min.js b/modules/system/assets/ui/storm-min.js index 8c58ca1b99..95e963f5e4 100644 --- a/modules/system/assets/ui/storm-min.js +++ b/modules/system/assets/ui/storm-min.js @@ -48,7 +48,7 @@ return buffer;};Writer.prototype._renderInverted=function(token,context,partials return this.renderTokens(token[4],context,partials,originalTemplate);};Writer.prototype._renderPartial=function(token,context,partials){if(!partials)return;var value=isFunction(partials)?partials(token[1]):partials[token[1]];if(value!=null) return this.renderTokens(this.parse(value),context,partials,value);};Writer.prototype._unescapedValue=function(token,context){var value=context.lookup(token[1]);if(value!=null) return value;};Writer.prototype._escapedValue=function(token,context){var value=context.lookup(token[1]);if(value!=null) -return mustache.escape(value);};Writer.prototype._rawValue=function(token){return token[1];};mustache.name="mustache.js";mustache.version="2.0.0";mustache.tags=["{{","}}"];var defaultWriter=new Writer();mustache.clearCache=function(){return defaultWriter.clearCache();};mustache.parse=function(template,tags){return defaultWriter.parse(template,tags);};mustache.render=function(template,view,partials){return defaultWriter.render(template,view,partials);};mustache.to_html=function(template,view,partials,send){var result=mustache.render(template,view,partials);if(isFunction(send)){send(result);}else{return result;}};mustache.escape=escapeHtml;mustache.Scanner=Scanner;mustache.Context=Context;mustache.Writer=Writer;}));!function(e,t,n){function r(e,t){return typeof e===t}function o(){var e,t,n,o,a,i,s;for(var c in w)if(w.hasOwnProperty(c)){if(e=[],t=w[c],t.name&&(e.push(t.name.toLowerCase()),t.options&&t.options.aliases&&t.options.aliases.length))for(n=0;nf;f++)if(m=e[f],g=G.style[m],s(m,"-")&&(m=d(m)),G.style[m]!==n){if(a||r(o,"undefined"))return c(),"pfx"==t?m:!0;try{G.style[m]=o}catch(y){}if(G.style[m]!=g)return c(),"pfx"==t?m:!0}return c(),!1}function y(e,t,n,o,a){var i=e.charAt(0).toUpperCase()+e.slice(1),s=(e+" "+U.join(i+" ")+i).split(" ");return r(t,"string")||r(t,"undefined")?v(s,t,o,a):(s=(e+" "+O.join(i+" ")+i).split(" "),p(s,t,n))}function b(e,t,r){return y(e,n,n,t,r)}function T(e,t){var n=e.deleteDatabase(t);n.onsuccess=function(){u("indexeddb.deletedatabase",!0)},n.onerror=function(){u("indexeddb.deletedatabase",!1)}}var x=[],w=[],S={_version:"3.6.0",_config:{classPrefix:"",enableClasses:!0,enableJSClass:!0,usePrefixes:!0},_q:[],on:function(e,t){var n=this;setTimeout(function(){t(n[e])},0)},addTest:function(e,t,n){w.push({name:e,fn:t,options:n})},addAsyncTest:function(e){w.push({name:null,fn:e})}},Modernizr=function(){};Modernizr.prototype=S,Modernizr=new Modernizr,Modernizr.addTest("applicationcache","applicationCache"in e),Modernizr.addTest("geolocation","geolocation"in navigator),Modernizr.addTest("history",function(){var t=navigator.userAgent;return-1===t.indexOf("Android 2.")&&-1===t.indexOf("Android 4.0")||-1===t.indexOf("Mobile Safari")||-1!==t.indexOf("Chrome")||-1!==t.indexOf("Windows Phone")||"file:"===location.protocol?e.history&&"pushState"in e.history:!1}),Modernizr.addTest("postmessage","postMessage"in e),Modernizr.addTest("svg",!!t.createElementNS&&!!t.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect);var C=!1;try{C="WebSocket"in e&&2===e.WebSocket.CLOSING}catch(E){}Modernizr.addTest("websockets",C),Modernizr.addTest("localstorage",function(){var e="modernizr";try{return localStorage.setItem(e,e),localStorage.removeItem(e),!0}catch(t){return!1}}),Modernizr.addTest("sessionstorage",function(){var e="modernizr";try{return sessionStorage.setItem(e,e),sessionStorage.removeItem(e),!0}catch(t){return!1}}),Modernizr.addTest("websqldatabase","openDatabase"in e),Modernizr.addTest("webworkers","Worker"in e);var _=S._config.usePrefixes?" -webkit- -moz- -o- -ms- ".split(" "):["",""];S._prefixes=_;var k=t.documentElement,P="svg"===k.nodeName.toLowerCase();P||!function(e,t){function n(e,t){var n=e.createElement("p"),r=e.getElementsByTagName("head")[0]||e.documentElement;return n.innerHTML="x",r.insertBefore(n.lastChild,r.firstChild)}function r(){var e=b.elements;return"string"==typeof e?e.split(" "):e}function o(e,t){var n=b.elements;"string"!=typeof n&&(n=n.join(" ")),"string"!=typeof e&&(e=e.join(" ")),b.elements=n+" "+e,l(t)}function a(e){var t=y[e[h]];return t||(t={},v++,e[h]=v,y[v]=t),t}function i(e,n,r){if(n||(n=t),u)return n.createElement(e);r||(r=a(n));var o;return o=r.cache[e]?r.cache[e].cloneNode():g.test(e)?(r.cache[e]=r.createElem(e)).cloneNode():r.createElem(e),!o.canHaveChildren||m.test(e)||o.tagUrn?o:r.frag.appendChild(o)}function s(e,n){if(e||(e=t),u)return e.createDocumentFragment();n=n||a(e);for(var o=n.frag.cloneNode(),i=0,s=r(),c=s.length;c>i;i++)o.createElement(s[i]);return o}function c(e,t){t.cache||(t.cache={},t.createElem=e.createElement,t.createFrag=e.createDocumentFragment,t.frag=t.createFrag()),e.createElement=function(n){return b.shivMethods?i(n,e,t):t.createElem(n)},e.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+r().join().replace(/[\w\-:]+/g,function(e){return t.createElem(e),t.frag.createElement(e),'c("'+e+'")'})+");return n}")(b,t.frag)}function l(e){e||(e=t);var r=a(e);return!b.shivCSS||d||r.hasCSS||(r.hasCSS=!!n(e,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),u||c(e,r),e}var d,u,f="3.7.3",p=e.html5||{},m=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,g=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,h="_html5shiv",v=0,y={};!function(){try{var e=t.createElement("a");e.innerHTML="",d="hidden"in e,u=1==e.childNodes.length||function(){t.createElement("a");var e=t.createDocumentFragment();return"undefined"==typeof e.cloneNode||"undefined"==typeof e.createDocumentFragment||"undefined"==typeof e.createElement}()}catch(n){d=!0,u=!0}}();var b={elements:p.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:f,shivCSS:p.shivCSS!==!1,supportsUnknownElements:u,shivMethods:p.shivMethods!==!1,type:"default",shivDocument:l,createElement:i,createDocumentFragment:s,addElements:o};e.html5=b,l(t),"object"==typeof module&&module.exports&&(module.exports=b)}("undefined"!=typeof e?e:this,t);var N="Moz O ms Webkit",O=S._config.usePrefixes?N.toLowerCase().split(" "):[];S._domPrefixes=O;var z=function(){function e(e,t){var o;return e?(t&&"string"!=typeof t||(t=i(t||"div")),e="on"+e,o=e in t,!o&&r&&(t.setAttribute||(t=i("div")),t.setAttribute(e,""),o="function"==typeof t[e],t[e]!==n&&(t[e]=n),t.removeAttribute(e)),o):!1}var r=!("onblur"in t.documentElement);return e}();S.hasEvent=z,Modernizr.addTest("hashchange",function(){return z("hashchange",e)===!1?!1:t.documentMode===n||t.documentMode>7}),Modernizr.addTest("audio",function(){var e=i("audio"),t=!1;try{t=!!e.canPlayType,t&&(t=new Boolean(t),t.ogg=e.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),t.mp3=e.canPlayType('audio/mpeg; codecs="mp3"').replace(/^no$/,""),t.opus=e.canPlayType('audio/ogg; codecs="opus"')||e.canPlayType('audio/webm; codecs="opus"').replace(/^no$/,""),t.wav=e.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),t.m4a=(e.canPlayType("audio/x-m4a;")||e.canPlayType("audio/aac;")).replace(/^no$/,""))}catch(n){}return t}),Modernizr.addTest("canvas",function(){var e=i("canvas");return!(!e.getContext||!e.getContext("2d"))}),Modernizr.addTest("canvastext",function(){return Modernizr.canvas===!1?!1:"function"==typeof i("canvas").getContext("2d").fillText}),Modernizr.addTest("video",function(){var e=i("video"),t=!1;try{t=!!e.canPlayType,t&&(t=new Boolean(t),t.ogg=e.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),t.h264=e.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),t.webm=e.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,""),t.vp9=e.canPlayType('video/webm; codecs="vp9"').replace(/^no$/,""),t.hls=e.canPlayType('application/x-mpegURL; codecs="avc1.42E01E"').replace(/^no$/,""))}catch(n){}return t}),Modernizr.addTest("webgl",function(){var t=i("canvas"),n="probablySupportsContext"in t?"probablySupportsContext":"supportsContext";return n in t?t[n]("webgl")||t[n]("experimental-webgl"):"WebGLRenderingContext"in e}),Modernizr.addTest("cssgradients",function(){for(var e,t="background-image:",n="gradient(linear,left top,right bottom,from(#9f9),to(white));",r="",o=0,a=_.length-1;a>o;o++)e=0===o?"to ":"",r+=t+_[o]+"linear-gradient("+e+"left top, #9f9, white);";Modernizr._config.usePrefixes&&(r+=t+"-webkit-"+n);var s=i("a"),c=s.style;return c.cssText=r,(""+c.backgroundImage).indexOf("gradient")>-1}),Modernizr.addTest("multiplebgs",function(){var e=i("a").style;return e.cssText="background:url(https://),url(https://),red url(https://)",/(url\s*\(.*?){3}/.test(e.background)}),Modernizr.addTest("opacity",function(){var e=i("a").style;return e.cssText=_.join("opacity:.55;"),/^0.55$/.test(e.opacity)}),Modernizr.addTest("rgba",function(){var e=i("a").style;return e.cssText="background-color:rgba(150,255,150,.5)",(""+e.backgroundColor).indexOf("rgba")>-1}),Modernizr.addTest("inlinesvg",function(){var e=i("div");return e.innerHTML="","http://www.w3.org/2000/svg"==("undefined"!=typeof SVGRect&&e.firstChild&&e.firstChild.namespaceURI)});var R=i("input"),A="autocomplete autofocus list placeholder max min multiple pattern required step".split(" "),M={};Modernizr.input=function(t){for(var n=0,r=t.length;r>n;n++)M[t[n]]=!!(t[n]in R);return M.list&&(M.list=!(!i("datalist")||!e.HTMLDataListElement)),M}(A);var $="search tel url email datetime date month week time datetime-local number range color".split(" "),B={};Modernizr.inputtypes=function(e){for(var r,o,a,i=e.length,s="1)",c=0;i>c;c++)R.setAttribute("type",r=e[c]),a="text"!==R.type&&"style"in R,a&&(R.value=s,R.style.cssText="position:absolute;visibility:hidden;",/^range$/.test(r)&&R.style.WebkitAppearance!==n?(k.appendChild(R),o=t.defaultView,a=o.getComputedStyle&&"textfield"!==o.getComputedStyle(R,null).WebkitAppearance&&0!==R.offsetHeight,k.removeChild(R)):/^(search|tel)$/.test(r)||(a=/^(url|email)$/.test(r)?R.checkValidity&&R.checkValidity()===!1:R.value!=s)),B[e[c]]=!!a;return B}($),Modernizr.addTest("hsla",function(){var e=i("a").style;return e.cssText="background-color:hsla(120,40%,100%,.5)",s(e.backgroundColor,"rgba")||s(e.backgroundColor,"hsla")});var j="CSS"in e&&"supports"in e.CSS,L="supportsCSS"in e;Modernizr.addTest("supports",j||L);var D={}.toString;Modernizr.addTest("svgclippaths",function(){return!!t.createElementNS&&/SVGClipPath/.test(D.call(t.createElementNS("http://www.w3.org/2000/svg","clipPath")))}),Modernizr.addTest("smil",function(){return!!t.createElementNS&&/SVGAnimate/.test(D.call(t.createElementNS("http://www.w3.org/2000/svg","animate")))});var F=function(){var t=e.matchMedia||e.msMatchMedia;return t?function(e){var n=t(e);return n&&n.matches||!1}:function(t){var n=!1;return l("@media "+t+" { #modernizr { position: absolute; } }",function(t){n="absolute"==(e.getComputedStyle?e.getComputedStyle(t,null):t.currentStyle).position}),n}}();S.mq=F;var I=S.testStyles=l,W=function(){var e=navigator.userAgent,t=e.match(/w(eb)?osbrowser/gi),n=e.match(/windows phone/gi)&&e.match(/iemobile\/([0-9])+/gi)&&parseFloat(RegExp.$1)>=9;return t||n}();W?Modernizr.addTest("fontface",!1):I('@font-face {font-family:"font";src:url("https://")}',function(e,n){var r=t.getElementById("smodernizr"),o=r.sheet||r.styleSheet,a=o?o.cssRules&&o.cssRules[0]?o.cssRules[0].cssText:o.cssText||"":"",i=/src/i.test(a)&&0===a.indexOf(n.split(" ")[0]);Modernizr.addTest("fontface",i)}),I('#modernizr{font:0/0 a}#modernizr:after{content:":)";visibility:hidden;font:7px/1 a}',function(e){Modernizr.addTest("generatedcontent",e.offsetHeight>=6)}),Modernizr.addTest("touchevents",function(){var n;if("ontouchstart"in e||e.DocumentTouch&&t instanceof DocumentTouch)n=!0;else{var r=["@media (",_.join("touch-enabled),("),"heartz",")","{#modernizr{top:9px;position:absolute}}"].join("");I(r,function(e){n=9===e.offsetTop})}return n});var U=S._config.usePrefixes?N.split(" "):[];S._cssomPrefixes=U;var V=function(t){var r,o=_.length,a=e.CSSRule;if("undefined"==typeof a)return n;if(!t)return!1;if(t=t.replace(/^@/,""),r=t.replace(/-/g,"_").toUpperCase()+"_RULE",r in a)return"@"+t;for(var i=0;o>i;i++){var s=_[i],c=s.toUpperCase()+"_"+r;if(c in a)return"@-"+s.toLowerCase()+"-"+t}return!1};S.atRule=V;var q;!function(){var e={}.hasOwnProperty;q=r(e,"undefined")||r(e.call,"undefined")?function(e,t){return t in e&&r(e.constructor.prototype[t],"undefined")}:function(t,n){return e.call(t,n)}}(),S._l={},S.on=function(e,t){this._l[e]||(this._l[e]=[]),this._l[e].push(t),Modernizr.hasOwnProperty(e)&&setTimeout(function(){Modernizr._trigger(e,Modernizr[e])},0)},S._trigger=function(e,t){if(this._l[e]){var n=this._l[e];setTimeout(function(){var e,r;for(e=0;e",r.insertBefore(n.lastChild,r.firstChild)}function f(){var e=h.elements;return"string"==typeof e?e.split(" "):e}function p(e){var t=c[e[r]];return t||(t={},d++,e[r]=d,c[d]=t),t}function l(e,t,n){return t||(t=i),s?t.createElement(e):(n||(n=p(t)),!(r=n.cache[e]?n.cache[e].cloneNode():a.test(e)?(n.cache[e]=n.createElem(e)).cloneNode():n.createElem(e)).canHaveChildren||o.test(e)||r.tagUrn?r:n.frag.appendChild(r));var r}function m(e){e||(e=i);var t=p(e);return!h.shivCSS||n||t.hasCSS||(t.hasCSS=!!u(e,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),s||function(t,n){n.cache||(n.cache={},n.createElem=t.createElement,n.createFrag=t.createDocumentFragment,n.frag=n.createFrag()),t.createElement=function(e){return h.shivMethods?l(e,t,n):n.createElem(e)},t.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+f().join().replace(/[\w\-:]+/g,function(e){return n.createElem(e),n.frag.createElement(e),'c("'+e+'")'})+");return n}")(h,n.frag)}(e,t),e}!function(){try{var e=i.createElement("a");e.innerHTML="",n="hidden"in e,s=1==e.childNodes.length||function(){i.createElement("a");var e=i.createDocumentFragment();return void 0===e.cloneNode||void 0===e.createDocumentFragment||void 0===e.createElement}()}catch(e){s=n=!0}}();var h={elements:t.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:"3.7.3",shivCSS:!1!==t.shivCSS,supportsUnknownElements:s,shivMethods:!1!==t.shivMethods,type:"default",shivDocument:m,createElement:l,createDocumentFragment:function(e,t){if(e||(e=i),s)return e.createDocumentFragment();for(var n=(t=t||p(e)).frag.cloneNode(),r=0,o=f(),a=o.length;r+~])("+f().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),a="$1"+y+"\\:$2";r--;)(t=n[r]=n[r].split("}"))[t.length-1]=t[t.length-1].replace(o,a),n[r]=t.join("}");return n.join("{")}(o.reverse().join("")),c=function(e){for(var t,n=e.getElementsByTagName("*"),r=n.length,o=RegExp("^(?:"+f().join("|")+")$","i"),a=[];r--;)t=n[r],o.test(t.nodeName)&&a.push(t.applyElement(T(t)));return a}(s),d=u(s,o)}),n.attachEvent("onafterprint",function(){!function(e){for(var t=e.length;t--;)e[t].removeNode()}(c),clearTimeout(e._removeSheetTimer),e._removeSheetTimer=setTimeout(l,500)}),s.printShived=!0,s}h.type+=" print",(h.shivPrint=x)(i),"object"==typeof module&&module.exports&&(module.exports=h)}(void 0!==f?f:this,u);var T=e._config.usePrefixes?t.split(" "):[];function x(e,t){return!!~(""+e).indexOf(t)}e._cssomPrefixes=T;var w={elem:v("modernizr")};c._q.push(function(){delete w.elem});var S={style:w.elem.style};function C(e){return e.replace(/([A-Z])/g,function(e,t){return"-"+t.toLowerCase()}).replace(/^ms-/,"-ms-")}function E(e,t,n){var r;if("getComputedStyle"in f){r=getComputedStyle.call(f,e,t);var o=f.console;if(null!==r)n&&(r=r.getPropertyValue(n));else if(o)o[o.error?"error":"log"].call(o,"getComputedStyle returning null, its possible modernizr test results are inaccurate")}else r=!t&&e.currentStyle&&e.currentStyle[n];return r}function k(e){return e.replace(/([a-z])-([a-z])/g,function(e,t,n){return t+n.toUpperCase()}).replace(/^-/,"")}function _(e,t,n,r){if(r=!m(r,"undefined")&&r,!m(n,"undefined")){var o=function(e,t){var n=e.length;if("CSS"in f&&"supports"in f.CSS){for(;n--;)if(f.CSS.supports(C(e[n]),t))return!0;return!1}if("CSSSupportsRule"in f){for(var r=[];n--;)r.push("("+C(e[n])+":"+t+")");return y("@supports ("+(r=r.join(" or "))+") { #modernizr { position: absolute; } }",function(e){return"absolute"===E(e,null,"position")})}return p}(e,n);if(!m(o,"undefined"))return o}for(var a,i,s,d,c,l=["modernizr","tspan","samp"];!S.style&&l.length;)a=!0,S.modElem=v(l.shift()),S.style=S.modElem.style;function u(){a&&(delete S.style,delete S.modElem)}for(s=e.length,i=0;i li',this.$tabsContainer).each(function(index){self.initTab(this)}) this.$el.on('close.oc.tab',function(ev,data){ev.preventDefault() var force=(data!==undefined&&data.force!==undefined)?data.force:false;self.closeTab($(ev.target).closest('ul.nav-tabs > li, div.tab-content > div'),force)}) -this.$el.on('mousedown',"li[data-tab-id]",function(ev){if(ev.which===2){$(ev.target).trigger('close.oc.tab');}}) +this.$el.on('mousedown',"li[data-tab-id]",function(ev){if(ev.key==='2'){$(ev.target).trigger('close.oc.tab');}}) this.$el.on('toggleCollapse.oc.tab',function(ev,data){ev.preventDefault() $(ev.target).closest('div.tab-content > div').toggleClass('collapsed')}) this.$el.on('modified.oc.tab',function(ev){ev.preventDefault() @@ -5223,7 +5223,7 @@ if(!this.triggerHiding()){ev.preventDefault() return false} this.applyValues()} InspectorPopup.prototype.onHide=function(ev){this.dispose()} -InspectorPopup.prototype.onPopoverKeyDown=function(ev){if(ev.keyCode==13){$(ev.currentTarget).trigger('close.oc.popover')}} +InspectorPopup.prototype.onPopoverKeyDown=function(ev){if(ev.key==='Enter'){$(ev.currentTarget).trigger('close.oc.popover')}} InspectorPopup.prototype.onPopupEditorDisplayed=function(){this.popoverObj.options.closeOnPageClick=false this.popoverObj.options.closeOnEsc=false} InspectorPopup.prototype.onPopupEditorHidden=function(){this.popoverObj.options.closeOnPageClick=true @@ -6367,8 +6367,8 @@ StringListAutocomplete.prototype.onCommand=function(ev){var command=ev.currentTa switch(command){case'create-item':this.createItem() break;case'delete-item':this.deleteItem() break;}} -StringListAutocomplete.prototype.onKeyDown=function(ev){if(ev.keyCode==40){return this.navigateDown(ev)} -else if(ev.keyCode==38){return this.navigateUp(ev)}} +StringListAutocomplete.prototype.onKeyDown=function(ev){if(ev.key==='ArrowDown'){return this.navigateDown(ev)} +else if(ev.key==='ArrowUp'){return this.navigateUp(ev)}} $.oc.inspector.propertyEditors.stringListAutocomplete=StringListAutocomplete}(window.jQuery);+function($){"use strict";var Base=$.oc.inspector.propertyEditors.popupBase,BaseProto=Base.prototype var DictionaryEditor=function(inspector,propertyDefinition,containerCell,group){this.keyValidationSet=null this.valueValidationSet=null @@ -6541,8 +6541,8 @@ DictionaryEditor.prototype.onCommand=function(ev){var command=ev.currentTarget.g switch(command){case'create-item':this.createItem() break;case'delete-item':this.deleteItem() break;}} -DictionaryEditor.prototype.onKeyDown=function(ev){if(ev.keyCode==40){return this.navigateDown(ev)} -else if(ev.keyCode==38){return this.navigateUp(ev)}} +DictionaryEditor.prototype.onKeyDown=function(ev){if(ev.key==='ArrowDown'){return this.navigateDown(ev)} +else if(ev.key==='ArrowUp'){return this.navigateUp(ev)}} $.oc.inspector.propertyEditors.dictionary=DictionaryEditor}(window.jQuery);+function($){"use strict";var Base=$.oc.inspector.propertyEditors.string,BaseProto=Base.prototype var AutocompleteEditor=function(inspector,propertyDefinition,containerCell,group){this.autoUpdateTimeout=null Base.call(this,inspector,propertyDefinition,containerCell,group)} From ff1ae457d244d5f4742e5566628cc340df7406db Mon Sep 17 00:00:00 2001 From: pavelmgn Date: Thu, 12 Sep 2019 09:22:08 +0500 Subject: [PATCH 009/157] Pass path by reference in media.file.upload (#4616) Credit to @pavelmgn. Refs: https://github.com/octobercms/october/issues/3124#issuecomment-529577947 --- modules/backend/widgets/MediaManager.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/backend/widgets/MediaManager.php b/modules/backend/widgets/MediaManager.php index f1e5e2c4c4..bfbd84c454 100644 --- a/modules/backend/widgets/MediaManager.php +++ b/modules/backend/widgets/MediaManager.php @@ -1576,18 +1576,18 @@ protected function checkUploadPostback() * * Example usage: * - * Event::listen('media.file.upload', function ((\Backend\Widgets\MediaManager) $mediaWidget, (string) $path, (\Symfony\Component\HttpFoundation\File\UploadedFile) $uploadedFile) { + * Event::listen('media.file.upload', function ((\Backend\Widgets\MediaManager) $mediaWidget, (string) &$path, (\Symfony\Component\HttpFoundation\File\UploadedFile) $uploadedFile) { * \Log::info($path . " was upoaded."); * }); * * Or * - * $mediaWidget->bindEvent('file.upload', function ((string) $path, (\Symfony\Component\HttpFoundation\File\UploadedFile) $uploadedFile) { + * $mediaWidget->bindEvent('file.upload', function ((string) &$path, (\Symfony\Component\HttpFoundation\File\UploadedFile) $uploadedFile) { * \Log::info($path . " was uploaded"); * }); * */ - $this->fireSystemEvent('media.file.upload', [$filePath, $uploadedFile]); + $this->fireSystemEvent('media.file.upload', [&$filePath, $uploadedFile]); $response = Response::make([ 'link' => MediaLibrary::url($filePath), From dd1a9f368ba383365d161bf15d0080b3488f3e67 Mon Sep 17 00:00:00 2001 From: Ben Thomson Date: Thu, 12 Sep 2019 22:34:54 +0800 Subject: [PATCH 010/157] Revert c5d0a467 (#3834) Reported issues with tables with constrained widths breaking content too much. Refs: https://github.com/octobercms/october/issues/4618 --- modules/system/assets/css/styles.css | 2 +- modules/system/assets/ui/less/site.normalize.less | 4 +--- modules/system/assets/ui/storm.css | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/modules/system/assets/css/styles.css b/modules/system/assets/css/styles.css index 713fddb5cb..f65f3bc8f8 100644 --- a/modules/system/assets/css/styles.css +++ b/modules/system/assets/css/styles.css @@ -70,7 +70,7 @@ fieldset {border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em} legend {border:0;padding:0} textarea {overflow:auto} optgroup {font-weight:bold} -table {border-collapse:collapse;border-spacing:0;table-layout:auto;word-wrap:break-word;word-break:break-all} +table {border-collapse:collapse;border-spacing:0;table-layout:auto} td, th {padding:0} *, diff --git a/modules/system/assets/ui/less/site.normalize.less b/modules/system/assets/ui/less/site.normalize.less index 3606c3e0c5..d40b1a8229 100644 --- a/modules/system/assets/ui/less/site.normalize.less +++ b/modules/system/assets/ui/less/site.normalize.less @@ -416,11 +416,9 @@ table { border-collapse: collapse; border-spacing: 0; table-layout: auto; - word-wrap: break-word; - word-break: break-all; } td, th { padding: 0; -} \ No newline at end of file +} diff --git a/modules/system/assets/ui/storm.css b/modules/system/assets/ui/storm.css index 73de67aa1e..1f4bfdad9e 100644 --- a/modules/system/assets/ui/storm.css +++ b/modules/system/assets/ui/storm.css @@ -70,7 +70,7 @@ fieldset {border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em} legend {border:0;padding:0} textarea {overflow:auto} optgroup {font-weight:bold} -table {border-collapse:collapse;border-spacing:0;table-layout:auto;word-wrap:break-word;word-break:break-all} +table {border-collapse:collapse;border-spacing:0;table-layout:auto} td, th {padding:0} *, From 2aa61ed60d8e89b530fd0b88cb527995822795ea Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Sat, 14 Sep 2019 16:11:16 +1000 Subject: [PATCH 011/157] Fixes keyboard support on checkboxes The keydown/keyup/input events were not working correctly. Also the $cb selector was not specific enough and was picking up on the hidden input used to define the default state. --- modules/system/assets/ui/js/checkbox.js | 9 ++------- modules/system/assets/ui/storm-min.js | 4 +--- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/modules/system/assets/ui/js/checkbox.js b/modules/system/assets/ui/js/checkbox.js index 1f6a6a14d6..fc61d6f919 100644 --- a/modules/system/assets/ui/js/checkbox.js +++ b/modules/system/assets/ui/js/checkbox.js @@ -5,14 +5,9 @@ (function($) { - $(document).on('keydown', 'div.custom-checkbox', function(e) { - if (e.key === '(Space character)' || e.key === 'Spacebar' || e.key === ' ') - e.preventDefault() - }) - - $(document).on('input', 'div.custom-checkbox', function(e) { + $(document).on('keypress', 'div.custom-checkbox', function(e) { if (e.key === '(Space character)' || e.key === 'Spacebar' || e.key === ' ') { - var $cb = $('input', this) + var $cb = $('input[type=checkbox]', this) if ($cb.data('oc-space-timestamp') == e.timeStamp) return diff --git a/modules/system/assets/ui/storm-min.js b/modules/system/assets/ui/storm-min.js index 95e963f5e4..3183ccd0e9 100644 --- a/modules/system/assets/ui/storm-min.js +++ b/modules/system/assets/ui/storm-min.js @@ -2800,9 +2800,7 @@ $(document).on('focus.autocomplete.data-api','[data-control="autocomplete"]',fun if($this.data('autocomplete'))return var opts=$this.data() if(opts.source){opts.source=paramToObj('data-source',opts.source)} -$this.autocomplete(opts)})}(window.jQuery);(function($){$(document).on('keydown','div.custom-checkbox',function(e){if(e.key==='(Space character)'||e.key==='Spacebar'||e.key===' ') -e.preventDefault()}) -$(document).on('input','div.custom-checkbox',function(e){if(e.key==='(Space character)'||e.key==='Spacebar'||e.key===' '){var $cb=$('input',this) +$this.autocomplete(opts)})}(window.jQuery);(function($){$(document).on('keypress','div.custom-checkbox',function(e){if(e.key==='(Space character)'||e.key==='Spacebar'||e.key===' '){var $cb=$('input[type=checkbox]',this) if($cb.data('oc-space-timestamp')==e.timeStamp) return $cb.get(0).checked=!$cb.get(0).checked From dae58d08a0f09dce799ebeab5c0a639c4f0d4ae9 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Sat, 14 Sep 2019 16:33:21 +1000 Subject: [PATCH 012/157] Add keyboard support to list items --- modules/system/assets/ui/js/list.rowlink.js | 15 ++++++++++++++- modules/system/assets/ui/storm-min.js | 10 +++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/modules/system/assets/ui/js/list.rowlink.js b/modules/system/assets/ui/js/list.rowlink.js index de8add4c37..4e395912ad 100644 --- a/modules/system/assets/ui/js/list.rowlink.js +++ b/modules/system/assets/ui/js/list.rowlink.js @@ -40,7 +40,7 @@ popup = link.is('[data-control=popup]'), request = link.is('[data-request]') - $(this).find('td').not('.' + options.excludeClass).click(function(e) { + function handleClick(e) { if ($(document.body).hasClass('drag')) { return } @@ -60,12 +60,25 @@ else { window.location = href } + } + + $(this).find('td').not('.' + options.excludeClass).click(function(e) { + handleClick(e) + }) + + $(this).on('keypress', function(e) { + if (e.key === '(Space character)' || e.key === 'Spacebar' || e.key === ' ') { + handleClick(e) + return false + } }) $(this).addClass(options.linkedClass) link.hide().after(link.html()) }) + // Add Keyboard Navigation to list rows + $('tr.rowlink').attr('tabindex', 0) } RowLink.DEFAULTS = { diff --git a/modules/system/assets/ui/storm-min.js b/modules/system/assets/ui/storm-min.js index 3183ccd0e9..7406fe89cc 100644 --- a/modules/system/assets/ui/storm-min.js +++ b/modules/system/assets/ui/storm-min.js @@ -4038,14 +4038,18 @@ var tr=this.$el.prop('tagName')=='TR'?this.$el:this.$el.find('tr:has(td)') tr.each(function(){var link=$(this).find(options.target).filter(function(){return!$(this).closest('td').hasClass(options.excludeClass)&&!$(this).hasClass(options.excludeClass)}).first() if(!link.length)return var href=link.attr('href'),onclick=(typeof link.get(0).onclick=="function")?link.get(0).onclick:null,popup=link.is('[data-control=popup]'),request=link.is('[data-request]') -$(this).find('td').not('.'+options.excludeClass).click(function(e){if($(document.body).hasClass('drag')){return} +function handleClick(e){if($(document.body).hasClass('drag')){return} if(onclick){onclick.apply(link.get(0))} else if(request){link.request()} else if(popup){link.popup()} else if(e.ctrlKey||e.metaKey){window.open(href)} -else{window.location=href}}) +else{window.location=href}} +$(this).find('td').not('.'+options.excludeClass).click(function(e){handleClick(e)}) +$(this).on('keypress',function(e){if(e.key==='(Space character)'||e.key==='Spacebar'||e.key===' '){handleClick(e) +return false}}) $(this).addClass(options.linkedClass) -link.hide().after(link.html())})} +link.hide().after(link.html())}) +$('tr.rowlink').attr('tabindex',0)} RowLink.DEFAULTS={target:'a',excludeClass:'nolink',linkedClass:'rowlink'} var old=$.fn.rowLink $.fn.rowLink=function(option){var args=Array.prototype.slice.call(arguments,1) From 0a71ebf6148dd31b9854b5bc150639b7b6283253 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Sat, 14 Sep 2019 17:29:31 +1000 Subject: [PATCH 013/157] Add a small JSON Parser to October framework lib (#4527) * Add a small JSON Parser to October framework lib --- .../assets/js/october.relation.js | 2 +- .../widgets/form/assets/js/october.form.js | 2 +- modules/system/assets/js/framework-min.js | 1 + .../assets/js/framework.combined-min.js | 3 +- .../system/assets/js/framework.combined.js | 1 + modules/system/assets/js/framework.extras.js | 3 + modules/system/assets/js/framework.js | 5 +- modules/system/assets/js/october.parser.js | 355 ++++++++++++++++++ modules/system/assets/ui/js/autocomplete.js | 2 +- modules/system/assets/ui/js/chart.line.js | 2 +- modules/system/assets/ui/js/popup.js | 2 +- 11 files changed, 371 insertions(+), 7 deletions(-) create mode 100644 modules/system/assets/js/october.parser.js diff --git a/modules/backend/behaviors/relationcontroller/assets/js/october.relation.js b/modules/backend/behaviors/relationcontroller/assets/js/october.relation.js index 80bf1bea4e..e7fb3164eb 100644 --- a/modules/backend/behaviors/relationcontroller/assets/js/october.relation.js +++ b/modules/backend/behaviors/relationcontroller/assets/js/october.relation.js @@ -87,7 +87,7 @@ if (typeof value == 'object') return value try { - return JSON.parse(JSON.stringify(eval("({" + value + "})"))) + return $.oc.JSON("{" + value + "}") } catch (e) { throw new Error('Error parsing the '+name+' attribute value. '+e) diff --git a/modules/backend/widgets/form/assets/js/october.form.js b/modules/backend/widgets/form/assets/js/october.form.js index 0936d2df35..bb0496527e 100644 --- a/modules/backend/widgets/form/assets/js/october.form.js +++ b/modules/backend/widgets/form/assets/js/october.form.js @@ -264,7 +264,7 @@ if (typeof value == 'object') return value try { - return JSON.parse(JSON.stringify(eval("({" + value + "})"))) + return $.oc.JSON("{" + value + "}") } catch (e) { throw new Error('Error parsing the '+name+' attribute value. '+e) diff --git a/modules/system/assets/js/framework-min.js b/modules/system/assets/js/framework-min.js index fde32c26d6..034ed6a23e 100644 --- a/modules/system/assets/js/framework-min.js +++ b/modules/system/assets/js/framework-min.js @@ -1,4 +1,5 @@ +"use strict";!function(){function a(e,r,n){for(var t="",o=r;o= "0" && str[pos] <= "9")) { + var body = ""; + for (var i = pos; i < str.length; i++) { + if (str[i] === "-" || str[i] === "+" || str[i] === "." || (str[i] >= "0" && str[i] <= "9")) { + body += str[i]; + } else { + return { + originLength: body.length, + body: body + }; + } + } + throw new Error("Broken JSON number body near " + body); + } + + // parse object + if (str[pos] === "{" || str[pos] === "[") { + var stack = [str[pos]]; + var body = str[pos]; + for (var i = pos + 1; i < str.length; i++) { + body += str[i]; + if (str[i] === "\\") { + if (i + 1 < str.length) body += str[i + 1]; + i++; + } else if (str[i] === "\"") { + if (stack[stack.length - 1] === "\"") { + stack.pop(); + } else if (stack[stack.length - 1] !== "'") { + stack.push(str[i]); + } + } else if (str[i] === "'") { + if (stack[stack.length - 1] === "'") { + stack.pop(); + } else if (stack[stack.length - 1] !== "\"") { + stack.push(str[i]); + } + } else if (stack[stack.length - 1] !== "\"" && stack[stack.length - 1] !== "'") { + if (str[i] === "{") { + stack.push("{"); + } else if (str[i] === "}") { + if (stack[stack.length - 1] === "{") { + stack.pop(); + } else { + throw new Error("Broken JSON " + (str[pos] === "{" ? "object" : "array") + " body near " + body); + } + } else if (str[i] === "[") { + stack.push("["); + } else if (str[i] === "]") { + if (stack[stack.length - 1] === "[") { + stack.pop(); + } else { + throw new Error("Broken JSON " + (str[pos] === "{" ? "object" : "array") + " body near " + body); + } + } + } + if (!stack.length) { + return { + originLength: i - pos, + body: body + }; + } + } + throw new Error("Broken JSON " + (str[pos] === "{" ? "object" : "array") + " body near " + body); + } + throw new Error("Broken JSON body near " + str.substr((pos - 5 >= 0) ? pos - 5 : 0, 50)); + } + + /* + * This is a char can be key head + * @param ch + * @returns {boolean} + */ + function canBeKeyHead(ch) { + if (ch[0] === "\\") return false; + if ((ch[0] >= 'a' && ch[0] <= 'z') || (ch[0] >= 'A' && ch[0] <= 'Z') || ch[0] === '_') return true; + if (ch[0] >= '0' && ch[0] <= '9') return true; + if (ch[0] === '$') return true; + if (ch.charCodeAt(0) > 255) return true; + return false; + } + + function isBlankChar(ch) { + return ch === " " || ch === "\n" || ch === "\t"; + } + + /* + * parse JSON + * @param str + */ + function parse(str) { + str = str.trim(); + if (!str.length) throw new Error("Broken JSON object."); + var result = ""; + + /* + * the mistake ',' + */ + while (str && str[0] === ",") { + str = str.substr(1); + } + + /* + * string + */ + if (str[0] === "\"" || str[0] === "'") { + if (str[str.length - 1] !== str[0]) { + throw new Error("Invalid string JSON object."); + } + + var body = "\""; + for (var i = 1; i < str.length; i++) { + if (str[i] === "\\") { + if (str[i + 1] === "'") { + body += str[i + 1] + } else { + body += str[i]; + body += str[i + 1]; + } + i++; + } else if (str[i] === str[0]) { + body += "\""; + return body + } else if (str[i] === "\"") { + body += "\\\"" + } else body += str[i]; + } + throw new Error("Invalid string JSON object."); + } + + /* + * boolean + */ + if (str === "true" || str === "false") { + return str; + } + + /* + * null + */ + if (str === "null") { + return "null"; + } + + /* + * number + */ + var num = parseFloat(str); + if (!isNaN(num)) { + return num.toString(); + } + + /* + * object + */ + if (str[0] === "{") { + var type = "needKey"; + var result = "{"; + + for (var i = 1; i < str.length; i++) { + if (isBlankChar(str[i])) { + continue; + } else if (type === "needKey" && (str[i] === "\"" || str[i] === "'")) { + var key = parseKey(str, i + 1, str[i]); + result += "\"" + key + "\""; + i += key.length; + i += 1; + type = "afterKey"; + } else if (type === "needKey" && canBeKeyHead(str[i])) { + var key = parseKey(str, i); + result += "\""; + result += key; + result += "\""; + i += key.length - 1; + type = "afterKey"; + } else if (type === "afterKey" && str[i] === ":") { + result += ":"; + type = ":"; + } else if (type === ":") { + var body = getBody(str, i); + + i = i + body.originLength - 1; + result += parse(body.body); + + type = "afterBody"; + } else if (type === "afterBody" || type === "needKey") { + var last = i; + while (str[last] === "," || isBlankChar(str[last])) { + last++; + } + if (str[last] === "}" && last === str.length - 1) { + while (result[result.length - 1] === ",") { + result = result.substr(0, result.length - 1); + } + result += "}"; + return result; + } else if (last !== i && result !== "{") { + result += ","; + type = "needKey"; + i = last - 1; + } + } + } + throw new Error("Broken JSON object near " + result); + } + + /* + * array + */ + if (str[0] === "[") { + var result = "["; + var type = "needBody"; + for (var i = 1; i < str.length; i++) { + if (" " === str[i] || "\n" === str[i] || "\t" === str[i]) { + continue; + } else if (type === "needBody") { + if (str[i] === ",") { + result += "null,"; + continue; + } + if (str[i] === "]" && i === str.length - 1) { + if (result[result.length - 1] === ",") result = result.substr(0, result.length - 1); + result += "]"; + return result; + } + + var body = getBody(str, i); + + i = i + body.originLength - 1; + result += parse(body.body); + + type = "afterBody"; + } else if (type === "afterBody") { + if (str[i] === ",") { + result += ","; + type = "needBody"; + + // deal with mistake "," + while (str[i + 1] === "," || isBlankChar(str[i + 1])) { + if (str[i + 1] === ",") result += "null,"; + i++; + } + } else if (str[i] === "]" && i === str.length - 1) { + result += "]"; + return result; + } + } + } + throw new Error("Broken JSON array near " + result); + } + } + + /* + * parse October JSON string into JSON object + * @param json + * @returns {*} + */ + if ($.oc === undefined) + $.oc = {} + + $.oc.JSON = function(json) { + var jsonString = parse(json); + return JSON.parse(jsonString); + }; + +})(); diff --git a/modules/system/assets/ui/js/autocomplete.js b/modules/system/assets/ui/js/autocomplete.js index dda0d799a0..3bf55ca29e 100644 --- a/modules/system/assets/ui/js/autocomplete.js +++ b/modules/system/assets/ui/js/autocomplete.js @@ -378,7 +378,7 @@ if (typeof value == 'object') return value try { - return JSON.parse(JSON.stringify(eval("({" + value + "})"))) + return $.oc.JSON("{" + value + "}") } catch (e) { throw new Error('Error parsing the '+name+' attribute value. '+e) diff --git a/modules/system/assets/ui/js/chart.line.js b/modules/system/assets/ui/js/chart.line.js index f89b412fab..d54fd030b3 100644 --- a/modules/system/assets/ui/js/chart.line.js +++ b/modules/system/assets/ui/js/chart.line.js @@ -80,7 +80,7 @@ var parsedOptions = {} try { - parsedOptions = JSON.parse(JSON.stringify(eval("({" + options.chartOptions + "})"))); + parsedOptions = $.oc.JSON("{" + value + "}"); } catch (e) { throw new Error('Error parsing the data-chart-options attribute value. '+e); } diff --git a/modules/system/assets/ui/js/popup.js b/modules/system/assets/ui/js/popup.js index 2ba8f348ec..0da4bc87d8 100644 --- a/modules/system/assets/ui/js/popup.js +++ b/modules/system/assets/ui/js/popup.js @@ -395,7 +395,7 @@ if (typeof value == 'object') return value try { - return JSON.parse(JSON.stringify(eval("({" + value + "})"))) + return $.oc.JSON("{" + value + "}") } catch (e) { throw new Error('Error parsing the '+name+' attribute value. '+e) From 12e585b7f55e5a627a618990a37b7e5f67aadda0 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Sat, 14 Sep 2019 17:38:52 +1000 Subject: [PATCH 014/157] Update jQuery mousewheel from v3.1.9 to v 3.2.0 (#4574) * Update jQuery mousewheel --- .../assets/ui/vendor/mousewheel/mousewheel.js | 157 +++++++++++------- 1 file changed, 97 insertions(+), 60 deletions(-) diff --git a/modules/system/assets/ui/vendor/mousewheel/mousewheel.js b/modules/system/assets/ui/vendor/mousewheel/mousewheel.js index a515e7e6a5..c50151a9ef 100644 --- a/modules/system/assets/ui/vendor/mousewheel/mousewheel.js +++ b/modules/system/assets/ui/vendor/mousewheel/mousewheel.js @@ -1,104 +1,124 @@ -/*! Copyright (c) 2013 Brandon Aaron (http://brandon.aaron.sh) - * Licensed under the MIT License (LICENSE.txt). - * - * Version: 3.1.9 - * - * Requires: jQuery 1.2.2+ +/*! + * jQuery Mousewheel v3.2.0 + * https://github.com/jquery/jquery-mousewheel */ -(function (factory) { - if ( typeof define === 'function' && define.amd ) { +( function( factory ) { + if ( typeof define === "function" && define.amd ) { + // AMD. Register as an anonymous module. - define(['jquery'], factory); - } else if (typeof exports === 'object') { + define( [ "jquery" ], factory ); + } else if ( typeof exports === "object" ) { + // Node/CommonJS style for Browserify module.exports = factory; } else { + // Browser globals - factory(jQuery); + factory( jQuery ); } -}(function ($) { +} )( function( $ ) { - var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'], - toBind = ( 'onwheel' in document || document.documentMode >= 9 ) ? - ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'], + var toFix = [ "wheel", "mousewheel", "DOMMouseScroll", "MozMousePixelScroll" ], + toBind = ( "onwheel" in window.document || window.document.documentMode >= 9 ) ? + [ "wheel" ] : [ "mousewheel", "DomMouseScroll", "MozMousePixelScroll" ], slice = Array.prototype.slice, nullLowestDeltaTimeout, lowestDelta; if ( $.event.fixHooks ) { for ( var i = toFix.length; i; ) { - $.event.fixHooks[ toFix[--i] ] = $.event.mouseHooks; + $.event.fixHooks[ toFix[ --i ] ] = $.event.mouseHooks; } } var special = $.event.special.mousewheel = { - version: '3.1.9', + version: "3.2.0", setup: function() { if ( this.addEventListener ) { for ( var i = toBind.length; i; ) { - this.addEventListener( toBind[--i], handler, false ); + this.addEventListener( toBind[ --i ], handler, false ); } } else { this.onmousewheel = handler; } + // Store the line height and page height for this particular element - $.data(this, 'mousewheel-line-height', special.getLineHeight(this)); - $.data(this, 'mousewheel-page-height', special.getPageHeight(this)); + $.data( this, "mousewheel-line-height", special.getLineHeight( this ) ); + $.data( this, "mousewheel-page-height", special.getPageHeight( this ) ); }, teardown: function() { if ( this.removeEventListener ) { for ( var i = toBind.length; i; ) { - this.removeEventListener( toBind[--i], handler, false ); + this.removeEventListener( toBind[ --i ], handler, false ); } } else { this.onmousewheel = null; } + + // Clean up the data we added to the element + $.removeData( this, "mousewheel-line-height" ); + $.removeData( this, "mousewheel-page-height" ); }, - getLineHeight: function(elem) { - return parseInt($(elem)['offsetParent' in $.fn ? 'offsetParent' : 'parent']().css('fontSize'), 10); + getLineHeight: function( elem ) { + var $elem = $( elem ), + $parent = $elem[ "offsetParent" in $.fn ? "offsetParent" : "parent" ](); + if ( !$parent.length ) { + $parent = $( "body" ); + } + return parseInt( $parent.css( "fontSize" ), 10 ) || + parseInt( $elem.css( "fontSize" ), 10 ) || 16; }, - getPageHeight: function(elem) { - return $(elem).height(); + getPageHeight: function( elem ) { + return $( elem ).height(); }, settings: { - adjustOldDeltas: true + adjustOldDeltas: true, // see shouldAdjustOldDeltas() below + normalizeOffset: true // calls getBoundingClientRect for each event } }; - $.fn.extend({ - mousewheel: function(fn) { - return fn ? this.bind('mousewheel', fn) : this.trigger('mousewheel'); + $.fn.extend( { + mousewheel: function( fn ) { + return fn ? this.on( "mousewheel", fn ) : this.trigger( "mousewheel" ); }, - unmousewheel: function(fn) { - return this.unbind('mousewheel', fn); + unmousewheel: function( fn ) { + return this.off( "mousewheel", fn ); } - }); + } ); - function handler(event) { + function handler( event ) { var orgEvent = event || window.event, - args = slice.call(arguments, 1), + args = slice.call( arguments, 1 ), delta = 0, deltaX = 0, deltaY = 0, absDelta = 0; - event = $.event.fix(orgEvent); - event.type = 'mousewheel'; + event = $.event.fix( orgEvent ); + event.type = "mousewheel"; // Old school scrollwheel delta - if ( 'detail' in orgEvent ) { deltaY = orgEvent.detail * -1; } - if ( 'wheelDelta' in orgEvent ) { deltaY = orgEvent.wheelDelta; } - if ( 'wheelDeltaY' in orgEvent ) { deltaY = orgEvent.wheelDeltaY; } - if ( 'wheelDeltaX' in orgEvent ) { deltaX = orgEvent.wheelDeltaX * -1; } + if ( "detail" in orgEvent ) { + deltaY = orgEvent.detail * -1; + } + if ( "wheelDelta" in orgEvent ) { + deltaY = orgEvent.wheelDelta; + } + if ( "wheelDeltaY" in orgEvent ) { + deltaY = orgEvent.wheelDeltaY; + } + if ( "wheelDeltaX" in orgEvent ) { + deltaX = orgEvent.wheelDeltaX * -1; + } // Firefox < 17 horizontal scrolling related to DOMMouseScroll event - if ( 'axis' in orgEvent && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) { + if ( "axis" in orgEvent && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) { deltaX = deltaY * -1; deltaY = 0; } @@ -107,17 +127,21 @@ delta = deltaY === 0 ? deltaX : deltaY; // New school wheel delta (wheel event) - if ( 'deltaY' in orgEvent ) { + if ( "deltaY" in orgEvent ) { deltaY = orgEvent.deltaY * -1; delta = deltaY; } - if ( 'deltaX' in orgEvent ) { + if ( "deltaX" in orgEvent ) { deltaX = orgEvent.deltaX; - if ( deltaY === 0 ) { delta = deltaX * -1; } + if ( deltaY === 0 ) { + delta = deltaX * -1; + } } // No change actually happened, no reason to go any further - if ( deltaY === 0 && deltaX === 0 ) { return; } + if ( deltaY === 0 && deltaX === 0 ) { + return; + } // Need to convert lines and pages to pixels if we aren't already in pixels // There are three delta modes: @@ -125,31 +149,32 @@ // * deltaMode 1 is by lines // * deltaMode 2 is by pages if ( orgEvent.deltaMode === 1 ) { - var lineHeight = $.data(this, 'mousewheel-line-height'); + var lineHeight = $.data( this, "mousewheel-line-height" ); delta *= lineHeight; deltaY *= lineHeight; deltaX *= lineHeight; } else if ( orgEvent.deltaMode === 2 ) { - var pageHeight = $.data(this, 'mousewheel-page-height'); + var pageHeight = $.data( this, "mousewheel-page-height" ); delta *= pageHeight; deltaY *= pageHeight; deltaX *= pageHeight; } // Store lowest absolute delta to normalize the delta values - absDelta = Math.max( Math.abs(deltaY), Math.abs(deltaX) ); + absDelta = Math.max( Math.abs( deltaY ), Math.abs( deltaX ) ); if ( !lowestDelta || absDelta < lowestDelta ) { lowestDelta = absDelta; // Adjust older deltas if necessary - if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) { + if ( shouldAdjustOldDeltas( orgEvent, absDelta ) ) { lowestDelta /= 40; } } // Adjust older deltas if necessary - if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) { + if ( shouldAdjustOldDeltas( orgEvent, absDelta ) ) { + // Divide all the things by 40! delta /= 40; deltaX /= 40; @@ -157,37 +182,48 @@ } // Get a whole, normalized value for the deltas - delta = Math[ delta >= 1 ? 'floor' : 'ceil' ](delta / lowestDelta); - deltaX = Math[ deltaX >= 1 ? 'floor' : 'ceil' ](deltaX / lowestDelta); - deltaY = Math[ deltaY >= 1 ? 'floor' : 'ceil' ](deltaY / lowestDelta); + delta = Math[ delta >= 1 ? "floor" : "ceil" ]( delta / lowestDelta ); + deltaX = Math[ deltaX >= 1 ? "floor" : "ceil" ]( deltaX / lowestDelta ); + deltaY = Math[ deltaY >= 1 ? "floor" : "ceil" ]( deltaY / lowestDelta ); + + // Normalise offsetX and offsetY properties + if ( special.settings.normalizeOffset && this.getBoundingClientRect ) { + var boundingRect = this.getBoundingClientRect(); + event.offsetX = event.clientX - boundingRect.left; + event.offsetY = event.clientY - boundingRect.top; + } // Add information to the event object event.deltaX = deltaX; event.deltaY = deltaY; event.deltaFactor = lowestDelta; + // Go ahead and set deltaMode to 0 since we converted to pixels // Although this is a little odd since we overwrite the deltaX/Y // properties with normalized deltas. event.deltaMode = 0; // Add event and delta to the front of the arguments - args.unshift(event, delta, deltaX, deltaY); + args.unshift( event, delta, deltaX, deltaY ); // Clearout lowestDelta after sometime to better // handle multiple device types that give different // a different lowestDelta // Ex: trackpad = 3 and mouse wheel = 120 - if (nullLowestDeltaTimeout) { clearTimeout(nullLowestDeltaTimeout); } - nullLowestDeltaTimeout = setTimeout(nullLowestDelta, 200); + if ( nullLowestDeltaTimeout ) { + window.clearTimeout( nullLowestDeltaTimeout ); + } + nullLowestDeltaTimeout = window.setTimeout( nullLowestDelta, 200 ); - return ($.event.dispatch || $.event.handle).apply(this, args); + return ( $.event.dispatch || $.event.handle ).apply( this, args ); } function nullLowestDelta() { lowestDelta = null; } - function shouldAdjustOldDeltas(orgEvent, absDelta) { + function shouldAdjustOldDeltas( orgEvent, absDelta ) { + // If this is an older event and the delta is divisable by 120, // then we are assuming that the browser is treating this as an // older mouse wheel event and that we should divide the deltas @@ -195,7 +231,8 @@ // Side note, this actually impacts the reported scroll distance // in older browsers and can cause scrolling to be slower than native. // Turn this off by setting $.event.special.mousewheel.settings.adjustOldDeltas to false. - return special.settings.adjustOldDeltas && orgEvent.type === 'mousewheel' && absDelta % 120 === 0; + return special.settings.adjustOldDeltas && orgEvent.type === "mousewheel" && + absDelta % 120 === 0; } -})); \ No newline at end of file +} ); From 6b37241ba775fea5b0b62c6a1baf5a8678ff15b1 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Sat, 14 Sep 2019 17:41:13 +1000 Subject: [PATCH 015/157] Recompile assets --- modules/system/assets/js/framework-min.js | 6 +-- .../assets/js/framework.combined-min.js | 45 ++++++++++++++++--- modules/system/assets/ui/storm-min.js | 35 ++++++++------- 3 files changed, 61 insertions(+), 25 deletions(-) diff --git a/modules/system/assets/js/framework-min.js b/modules/system/assets/js/framework-min.js index 034ed6a23e..019f4050f5 100644 --- a/modules/system/assets/js/framework-min.js +++ b/modules/system/assets/js/framework-min.js @@ -1,6 +1,4 @@ - -"use strict";!function(){function a(e,r,n){for(var t="",o=r;o="0"&&str[pos]<="9")){var body="";for(var i=pos;i="0"&&str[i]<="9")){body+=str[i];}else{return{originLength:body.length,body:body};}} +throw new Error("Broken JSON number body near "+body);} +if(str[pos]==="{"||str[pos]==="["){var stack=[str[pos]];var body=str[pos];for(var i=pos+1;i=0)?pos-5:0,50));} +function canBeKeyHead(ch){if(ch[0]==="\\")return false;if((ch[0]>='a'&&ch[0]<='z')||(ch[0]>='A'&&ch[0]<='Z')||ch[0]==='_')return true;if(ch[0]>='0'&&ch[0]<='9')return true;if(ch[0]==='$')return true;if(ch.charCodeAt(0)>255)return true;return false;} +function isBlankChar(ch){return ch===" "||ch==="\n"||ch==="\t";} +function parse(str){str=str.trim();if(!str.length)throw new Error("Broken JSON object.");var result="";while(str&&str[0]===","){str=str.substr(1);} +if(str[0]==="\""||str[0]==="'"){if(str[str.length-1]!==str[0]){throw new Error("Invalid string JSON object.");} +var body="\"";for(var i=1;i-1){return this;} return ret;}else{throw new Error('Invalid arguments for Select2: '+options);}};} if($.fn.select2.defaults==null){$.fn.select2.defaults=Defaults;} -return Select2;});return{define:S2.define,require:S2.require};}());var select2=S2.require('jquery.select2');jQuery.fn.select2.amd=S2;return select2;}));(function(factory){if(typeof define==='function'&&define.amd){define(['jquery'],factory);}else if(typeof exports==='object'){module.exports=factory;}else{factory(jQuery);}}(function($){var toFix=['wheel','mousewheel','DOMMouseScroll','MozMousePixelScroll'],toBind=('onwheel'in document||document.documentMode>=9)?['wheel']:['mousewheel','DomMouseScroll','MozMousePixelScroll'],slice=Array.prototype.slice,nullLowestDeltaTimeout,lowestDelta;if($.event.fixHooks){for(var i=toFix.length;i;){$.event.fixHooks[toFix[--i]]=$.event.mouseHooks;}} -var special=$.event.special.mousewheel={version:'3.1.9',setup:function(){if(this.addEventListener){for(var i=toBind.length;i;){this.addEventListener(toBind[--i],handler,false);}}else{this.onmousewheel=handler;} -$.data(this,'mousewheel-line-height',special.getLineHeight(this));$.data(this,'mousewheel-page-height',special.getPageHeight(this));},teardown:function(){if(this.removeEventListener){for(var i=toBind.length;i;){this.removeEventListener(toBind[--i],handler,false);}}else{this.onmousewheel=null;}},getLineHeight:function(elem){return parseInt($(elem)['offsetParent'in $.fn?'offsetParent':'parent']().css('fontSize'),10);},getPageHeight:function(elem){return $(elem).height();},settings:{adjustOldDeltas:true}};$.fn.extend({mousewheel:function(fn){return fn?this.bind('mousewheel',fn):this.trigger('mousewheel');},unmousewheel:function(fn){return this.unbind('mousewheel',fn);}});function handler(event){var orgEvent=event||window.event,args=slice.call(arguments,1),delta=0,deltaX=0,deltaY=0,absDelta=0;event=$.event.fix(orgEvent);event.type='mousewheel';if('detail'in orgEvent){deltaY=orgEvent.detail*-1;} -if('wheelDelta'in orgEvent){deltaY=orgEvent.wheelDelta;} -if('wheelDeltaY'in orgEvent){deltaY=orgEvent.wheelDeltaY;} -if('wheelDeltaX'in orgEvent){deltaX=orgEvent.wheelDeltaX*-1;} -if('axis'in orgEvent&&orgEvent.axis===orgEvent.HORIZONTAL_AXIS){deltaX=deltaY*-1;deltaY=0;} -delta=deltaY===0?deltaX:deltaY;if('deltaY'in orgEvent){deltaY=orgEvent.deltaY*-1;delta=deltaY;} -if('deltaX'in orgEvent){deltaX=orgEvent.deltaX;if(deltaY===0){delta=deltaX*-1;}} +return Select2;});return{define:S2.define,require:S2.require};}());var select2=S2.require('jquery.select2');jQuery.fn.select2.amd=S2;return select2;}));(function(factory){if(typeof define==="function"&&define.amd){define(["jquery"],factory);}else if(typeof exports==="object"){module.exports=factory;}else{factory(jQuery);}})(function($){var toFix=["wheel","mousewheel","DOMMouseScroll","MozMousePixelScroll"],toBind=("onwheel"in window.document||window.document.documentMode>=9)?["wheel"]:["mousewheel","DomMouseScroll","MozMousePixelScroll"],slice=Array.prototype.slice,nullLowestDeltaTimeout,lowestDelta;if($.event.fixHooks){for(var i=toFix.length;i;){$.event.fixHooks[toFix[--i]]=$.event.mouseHooks;}} +var special=$.event.special.mousewheel={version:"3.2.0",setup:function(){if(this.addEventListener){for(var i=toBind.length;i;){this.addEventListener(toBind[--i],handler,false);}}else{this.onmousewheel=handler;} +$.data(this,"mousewheel-line-height",special.getLineHeight(this));$.data(this,"mousewheel-page-height",special.getPageHeight(this));},teardown:function(){if(this.removeEventListener){for(var i=toBind.length;i;){this.removeEventListener(toBind[--i],handler,false);}}else{this.onmousewheel=null;} +$.removeData(this,"mousewheel-line-height");$.removeData(this,"mousewheel-page-height");},getLineHeight:function(elem){var $elem=$(elem),$parent=$elem["offsetParent"in $.fn?"offsetParent":"parent"]();if(!$parent.length){$parent=$("body");} +return parseInt($parent.css("fontSize"),10)||parseInt($elem.css("fontSize"),10)||16;},getPageHeight:function(elem){return $(elem).height();},settings:{adjustOldDeltas:true,normalizeOffset:true}};$.fn.extend({mousewheel:function(fn){return fn?this.on("mousewheel",fn):this.trigger("mousewheel");},unmousewheel:function(fn){return this.off("mousewheel",fn);}});function handler(event){var orgEvent=event||window.event,args=slice.call(arguments,1),delta=0,deltaX=0,deltaY=0,absDelta=0;event=$.event.fix(orgEvent);event.type="mousewheel";if("detail"in orgEvent){deltaY=orgEvent.detail*-1;} +if("wheelDelta"in orgEvent){deltaY=orgEvent.wheelDelta;} +if("wheelDeltaY"in orgEvent){deltaY=orgEvent.wheelDeltaY;} +if("wheelDeltaX"in orgEvent){deltaX=orgEvent.wheelDeltaX*-1;} +if("axis"in orgEvent&&orgEvent.axis===orgEvent.HORIZONTAL_AXIS){deltaX=deltaY*-1;deltaY=0;} +delta=deltaY===0?deltaX:deltaY;if("deltaY"in orgEvent){deltaY=orgEvent.deltaY*-1;delta=deltaY;} +if("deltaX"in orgEvent){deltaX=orgEvent.deltaX;if(deltaY===0){delta=deltaX*-1;}} if(deltaY===0&&deltaX===0){return;} -if(orgEvent.deltaMode===1){var lineHeight=$.data(this,'mousewheel-line-height');delta*=lineHeight;deltaY*=lineHeight;deltaX*=lineHeight;}else if(orgEvent.deltaMode===2){var pageHeight=$.data(this,'mousewheel-page-height');delta*=pageHeight;deltaY*=pageHeight;deltaX*=pageHeight;} +if(orgEvent.deltaMode===1){var lineHeight=$.data(this,"mousewheel-line-height");delta*=lineHeight;deltaY*=lineHeight;deltaX*=lineHeight;}else if(orgEvent.deltaMode===2){var pageHeight=$.data(this,"mousewheel-page-height");delta*=pageHeight;deltaY*=pageHeight;deltaX*=pageHeight;} absDelta=Math.max(Math.abs(deltaY),Math.abs(deltaX));if(!lowestDelta||absDelta=1?'floor':'ceil'](delta/lowestDelta);deltaX=Math[deltaX>=1?'floor':'ceil'](deltaX/lowestDelta);deltaY=Math[deltaY>=1?'floor':'ceil'](deltaY/lowestDelta);event.deltaX=deltaX;event.deltaY=deltaY;event.deltaFactor=lowestDelta;event.deltaMode=0;args.unshift(event,delta,deltaX,deltaY);if(nullLowestDeltaTimeout){clearTimeout(nullLowestDeltaTimeout);} -nullLowestDeltaTimeout=setTimeout(nullLowestDelta,200);return($.event.dispatch||$.event.handle).apply(this,args);} +delta=Math[delta>=1?"floor":"ceil"](delta/lowestDelta);deltaX=Math[deltaX>=1?"floor":"ceil"](deltaX/lowestDelta);deltaY=Math[deltaY>=1?"floor":"ceil"](deltaY/lowestDelta);if(special.settings.normalizeOffset&&this.getBoundingClientRect){var boundingRect=this.getBoundingClientRect();event.offsetX=event.clientX-boundingRect.left;event.offsetY=event.clientY-boundingRect.top;} +event.deltaX=deltaX;event.deltaY=deltaY;event.deltaFactor=lowestDelta;event.deltaMode=0;args.unshift(event,delta,deltaX,deltaY);if(nullLowestDeltaTimeout){window.clearTimeout(nullLowestDeltaTimeout);} +nullLowestDeltaTimeout=window.setTimeout(nullLowestDelta,200);return($.event.dispatch||$.event.handle).apply(this,args);} function nullLowestDelta(){lowestDelta=null;} -function shouldAdjustOldDeltas(orgEvent,absDelta){return special.settings.adjustOldDeltas&&orgEvent.type==='mousewheel'&&absDelta%120===0;}}));!function($,window,pluginName,undefined){var containerDefaults={drag:true,drop:true,exclude:"",nested:true,vertical:true},groupDefaults={afterMove:function($placeholder,container,$closestItemOrContainer){},containerPath:"",containerSelector:"ol, ul",distance:0,delay:0,handle:"",itemPath:"",itemSelector:"li",bodyClass:"dragging",draggedClass:"dragged",isValidTarget:function($item,container){return true},onCancel:function($item,container,_super,event){},onDrag:function($item,position,_super,event){$item.css(position)},onDragStart:function($item,container,_super,event){$item.css({height:$item.outerHeight(),width:$item.outerWidth()}) +function shouldAdjustOldDeltas(orgEvent,absDelta){return special.settings.adjustOldDeltas&&orgEvent.type==="mousewheel"&&absDelta%120===0;}});!function($,window,pluginName,undefined){var containerDefaults={drag:true,drop:true,exclude:"",nested:true,vertical:true},groupDefaults={afterMove:function($placeholder,container,$closestItemOrContainer){},containerPath:"",containerSelector:"ol, ul",distance:0,delay:0,handle:"",itemPath:"",itemSelector:"li",bodyClass:"dragging",draggedClass:"dragged",isValidTarget:function($item,container){return true},onCancel:function($item,container,_super,event){},onDrag:function($item,position,_super,event){$item.css(position)},onDragStart:function($item,container,_super,event){$item.css({height:$item.outerHeight(),width:$item.outerWidth()}) $item.addClass(container.group.options.draggedClass) $("body").addClass(container.group.options.bodyClass)},onDrop:function($item,container,_super,event){$item.removeClass(container.group.options.draggedClass).removeAttr("style") $("body").removeClass(container.group.options.bodyClass)},onMousedown:function($item,_super,event){if(!event.target.nodeName.match(/^(input|select|textarea)$/i)){event.preventDefault() @@ -2794,7 +2797,7 @@ $.fn.autocomplete.noConflict=function(){$.fn.autocomplete=old return this} function paramToObj(name,value){if(value===undefined)value='' if(typeof value=='object')return value -try{return JSON.parse(JSON.stringify(eval("({"+value+"})")))} +try{return $.oc.JSON("{"+value+"}")} catch(e){throw new Error('Error parsing the '+name+' attribute value. '+e)}} $(document).on('focus.autocomplete.data-api','[data-control="autocomplete"]',function(e){var $this=$(this) if($this.data('autocomplete'))return @@ -3853,7 +3856,7 @@ $.fn.popup.noConflict=function(){$.fn.popup=old return this} function paramToObj(name,value){if(value===undefined)value='' if(typeof value=='object')return value -try{return JSON.parse(JSON.stringify(eval("({"+value+"})")))} +try{return $.oc.JSON("{"+value+"}")} catch(e){throw new Error('Error parsing the '+name+' attribute value. '+e)}} $(document).on('click.oc.popup','[data-control="popup"]',function(event){event.preventDefault() $(this).popup()});$(document).on('ajaxPromise','[data-popup-load-indicator]',function(event,context){if($(this).data('request')!=context.handler)return @@ -3896,7 +3899,7 @@ $.oc.chartUtils=new ChartUtils();}(window.jQuery);+function($){"use strict";var this.chartOptions={xaxis:{mode:"time",tickLength:5},selection:{mode:"x"},grid:{markingsColor:"rgba(0,0,0, 0.02)",backgroundColor:{colors:["#fff","#fff"]},borderColor:"#7bafcc",borderWidth:0,color:"#ddd",hoverable:true,clickable:true,labelMargin:10},series:{lines:{show:true,fill:true},points:{show:true}},tooltip:true,tooltipOpts:{defaultTheme:false,content:"%x: %y",dateFormat:"%y-%0m-%0d",shifts:{x:10,y:20}},legend:{show:true,noColumns:2}} this.defaultDataSetOptions={shadowSize:0} var parsedOptions={} -try{parsedOptions=JSON.parse(JSON.stringify(eval("({"+options.chartOptions+"})")));}catch(e){throw new Error('Error parsing the data-chart-options attribute value. '+e);} +try{parsedOptions=$.oc.JSON("{"+value+"}");}catch(e){throw new Error('Error parsing the data-chart-options attribute value. '+e);} this.chartOptions=$.extend({},this.chartOptions,parsedOptions) this.options=options this.$el=$(element) From 279e038617e291d9afb64ed2fc3cee0eebbe3eb1 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Sat, 14 Sep 2019 17:56:18 +1000 Subject: [PATCH 016/157] Include the JSON parser natively in framework.js We've also included it as a separate framework.parser.js file in case its needed by some external lib, such as Storm UI --- .../assets/js/october.relation.js | 6 +- .../widgets/form/assets/js/october.form.js | 2 +- modules/system/assets/js/framework-min.js | 42 ++- .../assets/js/framework.combined-min.js | 79 ++--- .../system/assets/js/framework.combined.js | 3 +- modules/system/assets/js/framework.extras.js | 5 +- modules/system/assets/js/framework.js | 332 +++++++++++++++++- ...{october.parser.js => framework.parser.js} | 49 +-- modules/system/assets/ui/js/autocomplete.js | 4 +- modules/system/assets/ui/js/chart.line.js | 18 +- modules/system/assets/ui/js/popup.js | 2 +- modules/system/assets/ui/storm-min.js | 6 +- 12 files changed, 438 insertions(+), 110 deletions(-) rename modules/system/assets/js/{october.parser.js => framework.parser.js} (94%) diff --git a/modules/backend/behaviors/relationcontroller/assets/js/october.relation.js b/modules/backend/behaviors/relationcontroller/assets/js/october.relation.js index e7fb3164eb..126e39284c 100644 --- a/modules/backend/behaviors/relationcontroller/assets/js/october.relation.js +++ b/modules/backend/behaviors/relationcontroller/assets/js/october.relation.js @@ -70,7 +70,7 @@ /* * This function transfers the supplied variables as hidden form inputs, - * to any popup that is spawned within the supplied container. The spawned + * to any popup that is spawned within the supplied container. The spawned * popup must contain a form element. */ this.bindToPopups = function(container, vars) { @@ -87,7 +87,7 @@ if (typeof value == 'object') return value try { - return $.oc.JSON("{" + value + "}") + return ocJSON("{" + value + "}") } catch (e) { throw new Error('Error parsing the '+name+' attribute value. '+e) @@ -97,4 +97,4 @@ } $.oc.relationBehavior = new RelationBehavior; -}(window.jQuery); \ No newline at end of file +}(window.jQuery); diff --git a/modules/backend/widgets/form/assets/js/october.form.js b/modules/backend/widgets/form/assets/js/october.form.js index bb0496527e..2a95c5aaea 100644 --- a/modules/backend/widgets/form/assets/js/october.form.js +++ b/modules/backend/widgets/form/assets/js/october.form.js @@ -264,7 +264,7 @@ if (typeof value == 'object') return value try { - return $.oc.JSON("{" + value + "}") + return ocJSON("{" + value + "}") } catch (e) { throw new Error('Error parsing the '+name+' attribute value. '+e) diff --git a/modules/system/assets/js/framework-min.js b/modules/system/assets/js/framework-min.js index 019f4050f5..e519b55f99 100644 --- a/modules/system/assets/js/framework-min.js +++ b/modules/system/assets/js/framework-min.js @@ -1,4 +1,5 @@ -"use strict";!function(){function a(e,r,n){for(var t="",o=r;o="0"&&str[pos]<="9")){var body="";for(var i=pos;i="0"&&str[i]<="9")){body+=str[i];}else{return{originLength:body.length,body:body};}} +throw new Error("Broken JSON number body near "+body);} +if(str[pos]==="{"||str[pos]==="["){var stack=[str[pos]];var body=str[pos];for(var i=pos+1;i=0)?pos-5:0,50));} +function canBeKeyHead(ch){if(ch[0]==="\\")return false;if((ch[0]>='a'&&ch[0]<='z')||(ch[0]>='A'&&ch[0]<='Z')||ch[0]==='_')return true;if(ch[0]>='0'&&ch[0]<='9')return true;if(ch[0]==='$')return true;if(ch.charCodeAt(0)>255)return true;return false;} +function isBlankChar(ch){return ch===" "||ch==="\n"||ch==="\t";} +function parse(str){str=str.trim();if(!str.length)throw new Error("Broken JSON object.");var result="";while(str&&str[0]===","){str=str.substr(1);} +if(str[0]==="\""||str[0]==="'"){if(str[str.length-1]!==str[0]){throw new Error("Invalid string JSON object.");} +var body="\"";for(var i=1;i="0"&&str[pos]<="9")){var body="";for(var i=pos;i="0"&&str[i]<="9")){body+=str[i];}else{return{originLength:body.length,body:body};}} -throw new Error("Broken JSON number body near "+body);} -if(str[pos]==="{"||str[pos]==="["){var stack=[str[pos]];var body=str[pos];for(var i=pos+1;i=0)?pos-5:0,50));} -function canBeKeyHead(ch){if(ch[0]==="\\")return false;if((ch[0]>='a'&&ch[0]<='z')||(ch[0]>='A'&&ch[0]<='Z')||ch[0]==='_')return true;if(ch[0]>='0'&&ch[0]<='9')return true;if(ch[0]==='$')return true;if(ch.charCodeAt(0)>255)return true;return false;} -function isBlankChar(ch){return ch===" "||ch==="\n"||ch==="\t";} -function parse(str){str=str.trim();if(!str.length)throw new Error("Broken JSON object.");var result="";while(str&&str[0]===","){str=str.substr(1);} -if(str[0]==="\""||str[0]==="'"){if(str[str.length-1]!==str[0]){throw new Error("Invalid string JSON object.");} -var body="\"";for(var i=1;i="0"&&str[pos]<="9")){var body="";for(var i=pos;i="0"&&str[i]<="9")){body+=str[i];}else{return{originLength:body.length,body:body};}} +throw new Error("Broken JSON number body near "+body);} +if(str[pos]==="{"||str[pos]==="["){var stack=[str[pos]];var body=str[pos];for(var i=pos+1;i=0)?pos-5:0,50));} +function canBeKeyHead(ch){if(ch[0]==="\\")return false;if((ch[0]>='a'&&ch[0]<='z')||(ch[0]>='A'&&ch[0]<='Z')||ch[0]==='_')return true;if(ch[0]>='0'&&ch[0]<='9')return true;if(ch[0]==='$')return true;if(ch.charCodeAt(0)>255)return true;return false;} +function isBlankChar(ch){return ch===" "||ch==="\n"||ch==="\t";} +function parse(str){str=str.trim();if(!str.length)throw new Error("Broken JSON object.");var result="";while(str&&str[0]===","){str=str.substr(1);} +if(str[0]==="\""||str[0]==="'"){if(str[str.length-1]!==str[0]){throw new Error("Invalid string JSON object.");} +var body="\"";for(var i=1;i= "0" && str[pos] <= "9")) { + var body = ""; + for (var i = pos; i < str.length; i++) { + if (str[i] === "-" || str[i] === "+" || str[i] === "." || (str[i] >= "0" && str[i] <= "9")) { + body += str[i]; + } else { + return { + originLength: body.length, + body: body + }; + } + } + throw new Error("Broken JSON number body near " + body); + } + + // parse object + if (str[pos] === "{" || str[pos] === "[") { + var stack = [str[pos]]; + var body = str[pos]; + for (var i = pos + 1; i < str.length; i++) { + body += str[i]; + if (str[i] === "\\") { + if (i + 1 < str.length) body += str[i + 1]; + i++; + } else if (str[i] === "\"") { + if (stack[stack.length - 1] === "\"") { + stack.pop(); + } else if (stack[stack.length - 1] !== "'") { + stack.push(str[i]); + } + } else if (str[i] === "'") { + if (stack[stack.length - 1] === "'") { + stack.pop(); + } else if (stack[stack.length - 1] !== "\"") { + stack.push(str[i]); + } + } else if (stack[stack.length - 1] !== "\"" && stack[stack.length - 1] !== "'") { + if (str[i] === "{") { + stack.push("{"); + } else if (str[i] === "}") { + if (stack[stack.length - 1] === "{") { + stack.pop(); + } else { + throw new Error("Broken JSON " + (str[pos] === "{" ? "object" : "array") + " body near " + body); + } + } else if (str[i] === "[") { + stack.push("["); + } else if (str[i] === "]") { + if (stack[stack.length - 1] === "[") { + stack.pop(); + } else { + throw new Error("Broken JSON " + (str[pos] === "{" ? "object" : "array") + " body near " + body); + } + } + } + if (!stack.length) { + return { + originLength: i - pos, + body: body + }; + } + } + throw new Error("Broken JSON " + (str[pos] === "{" ? "object" : "array") + " body near " + body); + } + throw new Error("Broken JSON body near " + str.substr((pos - 5 >= 0) ? pos - 5 : 0, 50)); + } + + function canBeKeyHead(ch) { + if (ch[0] === "\\") return false; + if ((ch[0] >= 'a' && ch[0] <= 'z') || (ch[0] >= 'A' && ch[0] <= 'Z') || ch[0] === '_') return true; + if (ch[0] >= '0' && ch[0] <= '9') return true; + if (ch[0] === '$') return true; + if (ch.charCodeAt(0) > 255) return true; + return false; + } + + function isBlankChar(ch) { + return ch === " " || ch === "\n" || ch === "\t"; + } + + function parse(str) { + str = str.trim(); + if (!str.length) throw new Error("Broken JSON object."); + var result = ""; + + /* + * the mistake ',' + */ + while (str && str[0] === ",") { + str = str.substr(1); + } + + /* + * string + */ + if (str[0] === "\"" || str[0] === "'") { + if (str[str.length - 1] !== str[0]) { + throw new Error("Invalid string JSON object."); + } + + var body = "\""; + for (var i = 1; i < str.length; i++) { + if (str[i] === "\\") { + if (str[i + 1] === "'") { + body += str[i + 1] + } else { + body += str[i]; + body += str[i + 1]; + } + i++; + } else if (str[i] === str[0]) { + body += "\""; + return body + } else if (str[i] === "\"") { + body += "\\\"" + } else body += str[i]; + } + throw new Error("Invalid string JSON object."); + } + + /* + * boolean + */ + if (str === "true" || str === "false") { + return str; + } + + /* + * null + */ + if (str === "null") { + return "null"; + } + + /* + * number + */ + var num = parseFloat(str); + if (!isNaN(num)) { + return num.toString(); + } + + /* + * object + */ + if (str[0] === "{") { + var type = "needKey"; + var result = "{"; + + for (var i = 1; i < str.length; i++) { + if (isBlankChar(str[i])) { + continue; + } else if (type === "needKey" && (str[i] === "\"" || str[i] === "'")) { + var key = parseKey(str, i + 1, str[i]); + result += "\"" + key + "\""; + i += key.length; + i += 1; + type = "afterKey"; + } else if (type === "needKey" && canBeKeyHead(str[i])) { + var key = parseKey(str, i); + result += "\""; + result += key; + result += "\""; + i += key.length - 1; + type = "afterKey"; + } else if (type === "afterKey" && str[i] === ":") { + result += ":"; + type = ":"; + } else if (type === ":") { + var body = getBody(str, i); + + i = i + body.originLength - 1; + result += parse(body.body); + + type = "afterBody"; + } else if (type === "afterBody" || type === "needKey") { + var last = i; + while (str[last] === "," || isBlankChar(str[last])) { + last++; + } + if (str[last] === "}" && last === str.length - 1) { + while (result[result.length - 1] === ",") { + result = result.substr(0, result.length - 1); + } + result += "}"; + return result; + } else if (last !== i && result !== "{") { + result += ","; + type = "needKey"; + i = last - 1; + } + } + } + throw new Error("Broken JSON object near " + result); + } + + /* + * array + */ + if (str[0] === "[") { + var result = "["; + var type = "needBody"; + for (var i = 1; i < str.length; i++) { + if (" " === str[i] || "\n" === str[i] || "\t" === str[i]) { + continue; + } else if (type === "needBody") { + if (str[i] === ",") { + result += "null,"; + continue; + } + if (str[i] === "]" && i === str.length - 1) { + if (result[result.length - 1] === ",") result = result.substr(0, result.length - 1); + result += "]"; + return result; + } + + var body = getBody(str, i); + + i = i + body.originLength - 1; + result += parse(body.body); + + type = "afterBody"; + } else if (type === "afterBody") { + if (str[i] === ",") { + result += ","; + type = "needBody"; + + // deal with mistake "," + while (str[i + 1] === "," || isBlankChar(str[i + 1])) { + if (str[i + 1] === ",") result += "null,"; + i++; + } + } else if (str[i] === "]" && i === str.length - 1) { + result += "]"; + return result; + } + } + } + throw new Error("Broken JSON array near " + result); + } + } + + // Global function + window.ocJSON = function(json) { + var jsonString = parse(json); + return JSON.parse(jsonString); + }; + +}(window); diff --git a/modules/system/assets/js/october.parser.js b/modules/system/assets/js/framework.parser.js similarity index 94% rename from modules/system/assets/js/october.parser.js rename to modules/system/assets/js/framework.parser.js index 62e4e23e69..6a9aad0554 100644 --- a/modules/system/assets/js/october.parser.js +++ b/modules/system/assets/js/framework.parser.js @@ -1,16 +1,13 @@ -/* - * October CMS JSON Parser - */ -"use strict"; +/* ======================================================================== + * OctoberCMS: front-end JavaScript parser + * http://octobercms.com + * + * (Note: This lib is included manually in the framework.js file) + * ======================================================================== + * Copyright 2016-2020 Alexey Bobkov, Samuel Georges + * ======================================================================== */ -(function() { - /** - * parse key - * @param str - * @param pos - * @param quote - * @returns {string} - */ ++function(window) { "use strict"; function parseKey(str, pos, quote) { var key = ""; for (var i = pos; i < str.length; i++) { @@ -30,12 +27,6 @@ throw new Error("Broken JSON syntax near " + key); } - /* - * get body - * @param str - * @param pos - * @returns {*} - */ function getBody(str, pos) { // parse string body if (str[pos] === "\"" || str[pos] === "'") { @@ -155,11 +146,6 @@ throw new Error("Broken JSON body near " + str.substr((pos - 5 >= 0) ? pos - 5 : 0, 50)); } - /* - * This is a char can be key head - * @param ch - * @returns {boolean} - */ function canBeKeyHead(ch) { if (ch[0] === "\\") return false; if ((ch[0] >= 'a' && ch[0] <= 'z') || (ch[0] >= 'A' && ch[0] <= 'Z') || ch[0] === '_') return true; @@ -173,10 +159,6 @@ return ch === " " || ch === "\n" || ch === "\t"; } - /* - * parse JSON - * @param str - */ function parse(str) { str = str.trim(); if (!str.length) throw new Error("Broken JSON object."); @@ -339,17 +321,10 @@ } } - /* - * parse October JSON string into JSON object - * @param json - * @returns {*} - */ - if ($.oc === undefined) - $.oc = {} - - $.oc.JSON = function(json) { + // Global function + window.ocJSON = function(json) { var jsonString = parse(json); return JSON.parse(jsonString); }; -})(); +}(window); diff --git a/modules/system/assets/ui/js/autocomplete.js b/modules/system/assets/ui/js/autocomplete.js index 3bf55ca29e..1203ff46c6 100644 --- a/modules/system/assets/ui/js/autocomplete.js +++ b/modules/system/assets/ui/js/autocomplete.js @@ -1,6 +1,6 @@ /* * The autcomplete plugin, a forked version of Bootstrap's original typeahead plugin. - * + * * Data attributes: * - data-control="autocomplete" - enables the autocomplete plugin * @@ -378,7 +378,7 @@ if (typeof value == 'object') return value try { - return $.oc.JSON("{" + value + "}") + return ocJSON("{" + value + "}") } catch (e) { throw new Error('Error parsing the '+name+' attribute value. '+e) diff --git a/modules/system/assets/ui/js/chart.line.js b/modules/system/assets/ui/js/chart.line.js index d54fd030b3..ee41bedfa9 100644 --- a/modules/system/assets/ui/js/chart.line.js +++ b/modules/system/assets/ui/js/chart.line.js @@ -39,7 +39,7 @@ tickLength: 5 }, selection: { mode: "x" }, - grid: { + grid: { markingsColor: "rgba(0,0,0, 0.02)", backgroundColor: { colors: ["#fff", "#fff"] }, borderColor: "#7bafcc", @@ -80,7 +80,7 @@ var parsedOptions = {} try { - parsedOptions = $.oc.JSON("{" + value + "}"); + parsedOptions = ocJSON("{" + value + "}"); } catch (e) { throw new Error('Error parsing the data-chart-options attribute value. '+e); } @@ -102,15 +102,15 @@ if (this.options.zoomable) { this.$el.on("plotselected", function (event, ranges) { - var newCoords = { - xaxis: { min: ranges.xaxis.from, max: ranges.xaxis.to } + var newCoords = { + xaxis: { min: ranges.xaxis.from, max: ranges.xaxis.to } } - + $.plot(self.$el, self.fullDataSet, $.extend(true, {}, self.chartOptions, newCoords)) self.resetZoomLink.show() }); } - + /* * Markings Helper */ @@ -121,14 +121,14 @@ function weekendAreas(axes) { var markings = [], d = new Date(axes.xaxis.min); - + // Go to the first Saturday d.setUTCDate(d.getUTCDate() - ((d.getUTCDay() + 1) % 7)) d.setUTCSeconds(0) d.setUTCMinutes(0) d.setUTCHours(0) var i = d.getTime() - + do { // When we don't set yaxis, the rectangle automatically // extends to infinity upwards and downwards @@ -178,7 +178,7 @@ } /* - * Adds a data set to the chart. + * Adds a data set to the chart. * See https://github.com/flot/flot/blob/master/API.md#data-format for the list * of supported data set options. */ diff --git a/modules/system/assets/ui/js/popup.js b/modules/system/assets/ui/js/popup.js index 0da4bc87d8..bf3b05e405 100644 --- a/modules/system/assets/ui/js/popup.js +++ b/modules/system/assets/ui/js/popup.js @@ -395,7 +395,7 @@ if (typeof value == 'object') return value try { - return $.oc.JSON("{" + value + "}") + return ocJSON("{" + value + "}") } catch (e) { throw new Error('Error parsing the '+name+' attribute value. '+e) diff --git a/modules/system/assets/ui/storm-min.js b/modules/system/assets/ui/storm-min.js index cb672e04bb..54e1ec81a2 100644 --- a/modules/system/assets/ui/storm-min.js +++ b/modules/system/assets/ui/storm-min.js @@ -2797,7 +2797,7 @@ $.fn.autocomplete.noConflict=function(){$.fn.autocomplete=old return this} function paramToObj(name,value){if(value===undefined)value='' if(typeof value=='object')return value -try{return $.oc.JSON("{"+value+"}")} +try{return ocJSON("{"+value+"}")} catch(e){throw new Error('Error parsing the '+name+' attribute value. '+e)}} $(document).on('focus.autocomplete.data-api','[data-control="autocomplete"]',function(e){var $this=$(this) if($this.data('autocomplete'))return @@ -3856,7 +3856,7 @@ $.fn.popup.noConflict=function(){$.fn.popup=old return this} function paramToObj(name,value){if(value===undefined)value='' if(typeof value=='object')return value -try{return $.oc.JSON("{"+value+"}")} +try{return ocJSON("{"+value+"}")} catch(e){throw new Error('Error parsing the '+name+' attribute value. '+e)}} $(document).on('click.oc.popup','[data-control="popup"]',function(event){event.preventDefault() $(this).popup()});$(document).on('ajaxPromise','[data-popup-load-indicator]',function(event,context){if($(this).data('request')!=context.handler)return @@ -3899,7 +3899,7 @@ $.oc.chartUtils=new ChartUtils();}(window.jQuery);+function($){"use strict";var this.chartOptions={xaxis:{mode:"time",tickLength:5},selection:{mode:"x"},grid:{markingsColor:"rgba(0,0,0, 0.02)",backgroundColor:{colors:["#fff","#fff"]},borderColor:"#7bafcc",borderWidth:0,color:"#ddd",hoverable:true,clickable:true,labelMargin:10},series:{lines:{show:true,fill:true},points:{show:true}},tooltip:true,tooltipOpts:{defaultTheme:false,content:"%x: %y",dateFormat:"%y-%0m-%0d",shifts:{x:10,y:20}},legend:{show:true,noColumns:2}} this.defaultDataSetOptions={shadowSize:0} var parsedOptions={} -try{parsedOptions=$.oc.JSON("{"+value+"}");}catch(e){throw new Error('Error parsing the data-chart-options attribute value. '+e);} +try{parsedOptions=ocJSON("{"+value+"}");}catch(e){throw new Error('Error parsing the data-chart-options attribute value. '+e);} this.chartOptions=$.extend({},this.chartOptions,parsedOptions) this.options=options this.$el=$(element) From bdbd2f34fe243fd111d4a621d852f6cf8c3faf1f Mon Sep 17 00:00:00 2001 From: Dan Harrin Date: Sat, 14 Sep 2019 13:25:18 +0100 Subject: [PATCH 017/157] Replace use of parseJSON with JSON.parse (#4517) Credit to @DanHarrin --- .../reportcontainer/assets/js/reportcontainer.js | 2 +- modules/cms/assets/js/october.cmspage.js | 4 ++-- .../system/assets/ui/js/inspector.datainteraction.js | 4 ++-- .../system/assets/ui/js/inspector.editor.objectlist.js | 6 +++--- modules/system/assets/ui/js/inspector.wrapper.base.js | 4 ++-- modules/system/assets/ui/storm-min.js | 10 +++++----- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/modules/backend/widgets/reportcontainer/assets/js/reportcontainer.js b/modules/backend/widgets/reportcontainer/assets/js/reportcontainer.js index d623550da6..26fb910340 100644 --- a/modules/backend/widgets/reportcontainer/assets/js/reportcontainer.js +++ b/modules/backend/widgets/reportcontainer/assets/js/reportcontainer.js @@ -58,7 +58,7 @@ this.$el.on('hidden.oc.inspector', '[data-inspectable]', function() { var values = $('[data-inspector-values]', this).val(), - parsedValues = $.parseJSON(values), + parsedValues = JSON.parse(values), li = $(this).closest('li').get(0) self.$form.request(self.alias + '::onUpdateWidget', { diff --git a/modules/cms/assets/js/october.cmspage.js b/modules/cms/assets/js/october.cmspage.js index 728d099437..e4721abad6 100644 --- a/modules/cms/assets/js/october.cmspage.js +++ b/modules/cms/assets/js/october.cmspage.js @@ -397,7 +397,7 @@ CmsPage.prototype.onInspectorHidden = function(ev) { var element = ev.target, - values = $.parseJSON($('[data-inspector-values]', element).val()) + values = JSON.parse($('[data-inspector-values]', element).val()) $('[name="component_aliases[]"]', element).val(values['oc.alias']) $('span.alias', element).text(values['oc.alias']) @@ -405,7 +405,7 @@ CmsPage.prototype.onInspectorHiding = function(ev, values) { var element = ev.target, - values = $.parseJSON($('[data-inspector-values]', element).val()), + values = JSON.parse($('[data-inspector-values]', element).val()), alias = values['oc.alias'], $componentList = $('#cms-master-tabs > div.tab-content > .tab-pane.active .control-componentlist .layout'), $cell = $(ev.target).parent() diff --git a/modules/system/assets/ui/js/inspector.datainteraction.js b/modules/system/assets/ui/js/inspector.datainteraction.js index 90de00a5aa..f9bfbba39a 100644 --- a/modules/system/assets/ui/js/inspector.datainteraction.js +++ b/modules/system/assets/ui/js/inspector.datainteraction.js @@ -52,7 +52,7 @@ var valuesStr = $.trim(valuesField.value) try { - return valuesStr.length === 0 ? {} : $.parseJSON(valuesStr) + return valuesStr.length === 0 ? {} : JSON.parse(valuesStr) } catch (err) { throw new Error('Error parsing Inspector field values. ' + err) @@ -134,7 +134,7 @@ } try { - return $.parseJSON(configuration) + return JSON.parse(configuration) } catch(err) { throw new Error('Error parsing Inspector configuration. ' + err) diff --git a/modules/system/assets/ui/js/inspector.editor.objectlist.js b/modules/system/assets/ui/js/inspector.editor.objectlist.js index e116fdd3be..a8ed51d011 100644 --- a/modules/system/assets/ui/js/inspector.editor.objectlist.js +++ b/modules/system/assets/ui/js/inspector.editor.objectlist.js @@ -297,7 +297,7 @@ } var properties = this.propertyDefinition.itemProperties, - values = $.parseJSON(dataStr), + values = JSON.parse(dataStr), options = { enableExternalParameterEditor: false, onChange: this.proxy(this.onInspectorDataChange), @@ -447,7 +447,7 @@ for (var i = 0, len = dataRows.length; i < len; i++) { var dataRow = dataRows[i], - rowData = $.parseJSON(dataRow.getAttribute('data-inspector-values')) + rowData = JSON.parse(dataRow.getAttribute('data-inspector-values')) if (!this.isKeyValueMode()) { result.push(rowData) @@ -500,7 +500,7 @@ for (var i = 0, len = dataRows.length; i < len; i++) { var dataRow = dataRows[i], - rowData = $.parseJSON(dataRow.getAttribute('data-inspector-values')) + rowData = JSON.parse(dataRow.getAttribute('data-inspector-values')) if (selectedRow == dataRow) { continue diff --git a/modules/system/assets/ui/js/inspector.wrapper.base.js b/modules/system/assets/ui/js/inspector.wrapper.base.js index 4b69a358fe..ed80fa92e2 100644 --- a/modules/system/assets/ui/js/inspector.wrapper.base.js +++ b/modules/system/assets/ui/js/inspector.wrapper.base.js @@ -168,7 +168,7 @@ var valuesStr = $.trim($valuesField.val()) try { - return valuesStr.length === 0 ? {} : $.parseJSON(valuesStr) + return valuesStr.length === 0 ? {} : JSON.parse(valuesStr) } catch (err) { throw new Error('Error parsing Inspector field values. ' + err) @@ -338,7 +338,7 @@ } try { - return $.parseJSON(configuration) + return JSON.parse(configuration) } catch(err) { throw new Error('Error parsing Inspector configuration. ' + err) diff --git a/modules/system/assets/ui/storm-min.js b/modules/system/assets/ui/storm-min.js index 54e1ec81a2..e7dbf92aac 100644 --- a/modules/system/assets/ui/storm-min.js +++ b/modules/system/assets/ui/storm-min.js @@ -5097,7 +5097,7 @@ BaseWrapper.prototype.cleanupAfterSwitch=function(){this.switched=true this.dispose()} BaseWrapper.prototype.loadValues=function(configuration){var $valuesField=this.getElementValuesInput() if($valuesField.length>0){var valuesStr=$.trim($valuesField.val()) -try{return valuesStr.length===0?{}:$.parseJSON(valuesStr)} +try{return valuesStr.length===0?{}:JSON.parse(valuesStr)} catch(err){throw new Error('Error parsing Inspector field values. '+err)}} var values={},attributes=this.$element.get(0).attributes for(var i=0,len=attributes.length;i Date: Sat, 14 Sep 2019 06:27:24 -0600 Subject: [PATCH 018/157] Cleaning up spacing --- modules/backend/widgets/form/partials/_form_tabs.htm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/backend/widgets/form/partials/_form_tabs.htm b/modules/backend/widgets/form/partials/_form_tabs.htm index d762886445..f0de20330e 100644 --- a/modules/backend/widgets/form/partials/_form_tabs.htm +++ b/modules/backend/widgets/form/partials/_form_tabs.htm @@ -14,8 +14,8 @@
@@ -24,8 +24,8 @@
$fields): ?>
+ class="tab-pane getPaneCssClass($index, $name)) ?> " + id=""> makePartial('form_fields', ['fields' => $fields]) ?>
From a8fcad468303890c5d9e7beee4107ace87f212fb Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Wed, 18 Sep 2019 18:27:18 -0600 Subject: [PATCH 019/157] Added ability to specify a LESS file to be used as a default backend brand CSS override with the config item "brand.customLessPath" --- modules/backend/models/BrandSetting.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/modules/backend/models/BrandSetting.php b/modules/backend/models/BrandSetting.php index 10821fd0e8..bdd20bd220 100644 --- a/modules/backend/models/BrandSetting.php +++ b/modules/backend/models/BrandSetting.php @@ -80,6 +80,12 @@ public function initSettingsData() $this->secondary_color = $config->get('brand.secondaryColor', self::SECONDARY_COLOR); $this->accent_color = $config->get('brand.accentColor', self::ACCENT_COLOR); $this->menu_mode = $config->get('brand.menuMode', self::INLINE_MENU); + + // Attempt to load custom CSS + $brandCssPath = File::symbolizePath(Config::get('brand.customLessPath')); + if ($brandCssPath && File::exists($brandCssPath)) { + $this->custom_css = File::get($brandCssPath); + } } public function afterSave() From 06b5a943671a7a627350f44f4cbdbec7bd50c3ca Mon Sep 17 00:00:00 2001 From: Ben Thomson Date: Fri, 20 Sep 2019 08:21:32 +0800 Subject: [PATCH 020/157] Use develop branch of Rain library in Travis CI --- .travis.yml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 00e504a71b..5a9b015276 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,9 +20,16 @@ cache: - $HOME/.composer/cache/files install: - - travis_retry composer install --no-interaction --no-progress --no-suggest - -before_script: git reset --hard HEAD + - composer install --no-interaction --no-progress --no-suggest + # Reset October modules back to Git source + - git reset --hard HEAD + # Replace October library with `develop` branch + - rm -rf ./vendor/october/rain + - wget https://github.com/octobercms/library/archive/develop.zip -O ./vendor/october/develop.zip + - unzip ./vendor/october/develop.zip + - mv ./vendor/october/library-develop ./vendor/october/rain + # Dump autoload + - composer dump-autoload stages: - test From 1145b6564e66127914626519c1097f6e7f96f645 Mon Sep 17 00:00:00 2001 From: Ben Thomson Date: Fri, 20 Sep 2019 08:34:20 +0800 Subject: [PATCH 021/157] Diagnose Travis `mv` issue --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 5a9b015276..5c55d4dbde 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,8 @@ install: - rm -rf ./vendor/october/rain - wget https://github.com/octobercms/library/archive/develop.zip -O ./vendor/october/develop.zip - unzip ./vendor/october/develop.zip - - mv ./vendor/october/library-develop ./vendor/october/rain + - ls -la ./vendor/october/ + - mv ./vendor/october/library-develop/ ./vendor/october/rain # Dump autoload - composer dump-autoload From 6241585c6c52d02e9be53c2fd0f61fced6970cdb Mon Sep 17 00:00:00 2001 From: Ben Thomson Date: Fri, 20 Sep 2019 08:40:09 +0800 Subject: [PATCH 022/157] Fix Travis `unzip` and `mv` Rain library --- .travis.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5c55d4dbde..cd02f2cc89 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,9 +26,8 @@ install: # Replace October library with `develop` branch - rm -rf ./vendor/october/rain - wget https://github.com/octobercms/library/archive/develop.zip -O ./vendor/october/develop.zip - - unzip ./vendor/october/develop.zip - - ls -la ./vendor/october/ - - mv ./vendor/october/library-develop/ ./vendor/october/rain + - unzip ./vendor/october/develop.zip -d ./vendor/october + - mv ./vendor/october/library-develop ./vendor/october/rain # Dump autoload - composer dump-autoload From 138853634e348dbcd0272152af716cb7d8ab2576 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Sat, 21 Sep 2019 10:07:01 +1000 Subject: [PATCH 023/157] Add a working checkbox list doc code example to october website (#4600) --- modules/system/assets/ui/docs/checkbox.md | 38 +++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/modules/system/assets/ui/docs/checkbox.md b/modules/system/assets/ui/docs/checkbox.md index a286b62e66..d4276d9cdc 100644 --- a/modules/system/assets/ui/docs/checkbox.md +++ b/modules/system/assets/ui/docs/checkbox.md @@ -9,6 +9,44 @@ Allows a user to select from a small set of binary options.
+### Checkbox lists + +Allows a user to select from a list of binary options. + +
+ +
+ +
+
+ +
+
+ +
+
+ +
+

What cars would you like in your garage?

+
+ + +

Do not send new comment notifications.

+
+
+ + +

Send new comment notifications only to post author.

+
+
+ + +

Notify all users who have permissions to receive blog notifications.

+
+
+
+
+ ### Radio
From d4574e8f3559749b3e08997584b25b1ab22cd4d1 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Sat, 21 Sep 2019 10:39:46 +1000 Subject: [PATCH 024/157] Fix the Primary tabs overflow error (#4587) * Fix the overflow on the primary tabs --- modules/system/assets/ui/less/tab.less | 2 +- modules/system/assets/ui/storm.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/system/assets/ui/less/tab.less b/modules/system/assets/ui/less/tab.less index 90fae3ee62..1be5efeac0 100644 --- a/modules/system/assets/ui/less/tab.less +++ b/modules/system/assets/ui/less/tab.less @@ -250,7 +250,7 @@ position: absolute; bottom: 0; height: 1px; - width: 100%; + width: 100vw; z-index: @zindex-tab - 1; content: ' '; border-bottom: 2px solid @color-tab-active-border; diff --git a/modules/system/assets/ui/storm.css b/modules/system/assets/ui/storm.css index 1f4bfdad9e..600318f191 100644 --- a/modules/system/assets/ui/storm.css +++ b/modules/system/assets/ui/storm.css @@ -2872,7 +2872,7 @@ body.compact-container .control-breadcrumb {margin-top:0;margin-left:0;margin-ri .control-tabs.primary-tabs >div >div >ul.nav-tabs {position:relative;margin-left:0;margin-right:0} .control-tabs.primary-tabs >ul.nav-tabs:before, .control-tabs.primary-tabs >div >ul.nav-tabs:before, -.control-tabs.primary-tabs >div >div >ul.nav-tabs:before {position:absolute;bottom:0;height:1px;width:100%;z-index:9;content:' ';border-bottom:2px solid #d0d0d0} +.control-tabs.primary-tabs >div >div >ul.nav-tabs:before {position:absolute;bottom:0;height:1px;width:100vw;z-index:9;content:' ';border-bottom:2px solid #d0d0d0} .control-tabs.primary-tabs >ul.nav-tabs >li, .control-tabs.primary-tabs >div >ul.nav-tabs >li, .control-tabs.primary-tabs >div >div >ul.nav-tabs >li {padding-right:0;padding-left:0;margin-left:0;margin-right:-20px;background:transparent} From 47f906df1c86f3fe6143a369002fa3612e7d9d55 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Sat, 21 Sep 2019 11:57:53 +1000 Subject: [PATCH 025/157] Update the checkbox list widget (#4599) --- modules/backend/lang/ar/lang.php | 4 +- modules/backend/lang/be/lang.php | 4 +- modules/backend/lang/bg/lang.php | 4 +- modules/backend/lang/ca/lang.php | 4 +- modules/backend/lang/cs/lang.php | 4 +- modules/backend/lang/da/lang.php | 4 +- modules/backend/lang/de/lang.php | 4 +- modules/backend/lang/el/lang.php | 4 +- modules/backend/lang/en/lang.php | 4 +- modules/backend/lang/es-ar/lang.php | 4 +- modules/backend/lang/es/lang.php | 4 +- modules/backend/lang/et/lang.php | 4 +- modules/backend/lang/fa/lang.php | 4 +- modules/backend/lang/fi/lang.php | 4 +- modules/backend/lang/fr/lang.php | 4 +- modules/backend/lang/hu/lang.php | 4 +- modules/backend/lang/id/lang.php | 4 +- modules/backend/lang/it/lang.php | 4 +- modules/backend/lang/ja/lang.php | 4 +- modules/backend/lang/kr/lang.php | 4 +- modules/backend/lang/lt/lang.php | 4 +- modules/backend/lang/lv/lang.php | 4 +- modules/backend/lang/nb-no/lang.php | 4 +- modules/backend/lang/nl/lang.php | 4 +- modules/backend/lang/pl/lang.php | 4 +- modules/backend/lang/pt-br/lang.php | 4 +- modules/backend/lang/pt-pt/lang.php | 4 +- modules/backend/lang/ro/lang.php | 4 +- modules/backend/lang/ru/lang.php | 4 +- modules/backend/lang/sk/lang.php | 4 +- modules/backend/lang/sv/lang.php | 4 +- modules/backend/lang/th/lang.php | 4 +- modules/backend/lang/tr/lang.php | 4 +- modules/backend/lang/uk/lang.php | 4 +- modules/backend/lang/vn/lang.php | 4 +- modules/backend/lang/zh-cn/lang.php | 4 +- modules/backend/lang/zh-tw/lang.php | 4 +- .../form/partials/_field_checkboxlist.htm | 84 ++++++++++--------- modules/system/assets/ui/less/form.base.less | 2 +- modules/system/assets/ui/less/form.less | 37 +++++++- modules/system/assets/ui/storm.css | 9 +- 41 files changed, 164 insertions(+), 116 deletions(-) diff --git a/modules/backend/lang/ar/lang.php b/modules/backend/lang/ar/lang.php index 86a224b7d1..08e208c821 100644 --- a/modules/backend/lang/ar/lang.php +++ b/modules/backend/lang/ar/lang.php @@ -101,8 +101,8 @@ 'reload' => 'إعادة تحميل', 'complete' => 'تم', 'select' => 'تحديد', - 'select_all' => 'تحديد الكل', - 'select_none' => 'إلغاء التحديد', + 'select_all' => 'اختر الكل', + 'select_none' => 'لا تختر شيء', 'select_placeholder' => 'من فضلك اختار', 'insert_row' => 'إضافة سجل', 'return_to_list' => 'عودة للقائمة', diff --git a/modules/backend/lang/be/lang.php b/modules/backend/lang/be/lang.php index 8b76dc9ce5..d3d8c82abc 100644 --- a/modules/backend/lang/be/lang.php +++ b/modules/backend/lang/be/lang.php @@ -240,8 +240,8 @@ 'preview_no_files_message' => "Няма загружаных файлаў", 'preview_no_record_message' => "Няма выбраных запісаў", 'select' => "Выбраць", - 'select_all' => "усё", - 'select_none' => "нічога", + 'select_all' => "абраць усё", + 'select_none' => "выбраць няма", 'select_placeholder' => "Калі ласка, выберыце", 'insert_row' => "Уставіць радок", 'insert_row_below' => "Уставіць радок ніжэй", diff --git a/modules/backend/lang/bg/lang.php b/modules/backend/lang/bg/lang.php index 308d875a9a..2011a48d44 100644 --- a/modules/backend/lang/bg/lang.php +++ b/modules/backend/lang/bg/lang.php @@ -201,8 +201,8 @@ 'preview_no_files_message' => 'Все още няма качени файлове.', 'preview_no_record_message' => 'Не е избран запис.', 'select' => 'Избери', - 'select_all' => 'всичко', - 'select_none' => 'нищо', + 'select_all' => 'Избери всички', + 'select_none' => 'изберете никой', 'select_placeholder' => 'моля изберете', 'insert_row' => 'Вмъкни ред', 'insert_row_below' => 'Вмъкни ред По-долу', diff --git a/modules/backend/lang/ca/lang.php b/modules/backend/lang/ca/lang.php index 7cfbaf2693..5e0a041e4f 100644 --- a/modules/backend/lang/ca/lang.php +++ b/modules/backend/lang/ca/lang.php @@ -268,8 +268,8 @@ 'preview_no_media_message' => 'No hi ha medis seleccionats.', 'preview_no_record_message' => 'No hi ha cap registre seleccionat.', 'select' => 'Seleccionar', - 'select_all' => 'tots', - 'select_none' => 'cap', + 'select_all' => 'seleccionar tot', + 'select_none' => 'no selecciona cap', 'select_placeholder' => 'si us plau selecciona', 'insert_row' => 'Inserir fila', 'insert_row_below' => 'Inserir fila a sota', diff --git a/modules/backend/lang/cs/lang.php b/modules/backend/lang/cs/lang.php index a1b230f834..3caa0079b1 100644 --- a/modules/backend/lang/cs/lang.php +++ b/modules/backend/lang/cs/lang.php @@ -262,8 +262,8 @@ 'preview_no_media_message' => 'Žádné médium nebylo vybráno.', 'preview_no_record_message' => 'Žádný záznam není vybraný.', 'select' => 'Vybrat', - 'select_all' => 'Vše', - 'select_none' => 'Nic', + 'select_all' => 'vybrat vše', + 'select_none' => 'vyberte žádný', 'select_placeholder' => 'Prosím vyberte', 'insert_row' => 'Vložit řádek', 'insert_row_below' => 'Vložit řádek pod', diff --git a/modules/backend/lang/da/lang.php b/modules/backend/lang/da/lang.php index ca12b906ca..538f24dd40 100644 --- a/modules/backend/lang/da/lang.php +++ b/modules/backend/lang/da/lang.php @@ -235,8 +235,8 @@ 'preview_no_files_message' => 'Der er ikke uploadet nogle filer.', 'preview_no_record_message' => 'Der er ikke valgt nogen record.', 'select' => 'Vælg', - 'select_all' => 'alle', - 'select_none' => 'ingen', + 'select_all' => 'Vælg alle', + 'select_none' => 'vælg ingen', 'select_placeholder' => 'Vælg venligst', 'insert_row' => 'Indsæt Række', 'insert_row_below' => 'Indsæt Række Nedeunder', diff --git a/modules/backend/lang/de/lang.php b/modules/backend/lang/de/lang.php index 69cbfeeb65..d61f8af1b1 100644 --- a/modules/backend/lang/de/lang.php +++ b/modules/backend/lang/de/lang.php @@ -245,8 +245,8 @@ 'preview_no_media_message' => 'Es wurde keine Media-Datei ausgewählt.', 'preview_no_record_message' => 'Es ist kein Eintrag ausgewählt.', 'select' => 'Auswählen', - 'select_all' => 'Alle', - 'select_none' => 'Keine', + 'select_all' => 'Wählen Sie Alle', + 'select_none' => 'nichts ausgewählt', 'select_placeholder' => 'Bitte auswählen', 'insert_row' => 'Reihe einfügen', 'insert_row_below' => 'Neue Reihe darunter einfügen', diff --git a/modules/backend/lang/el/lang.php b/modules/backend/lang/el/lang.php index ac89c3af70..00c31fb20f 100644 --- a/modules/backend/lang/el/lang.php +++ b/modules/backend/lang/el/lang.php @@ -235,8 +235,8 @@ 'preview_no_files_message' => 'Δεν υπάρχουν αρχεία που ανέβηκαν.', 'preview_no_record_message' => 'Δεν είναι επιλεγμένη καμία εγγραφή.', 'select' => 'Επιλογή', - 'select_all' => 'όλα', - 'select_none' => 'κανένα', + 'select_all' => 'επιλογή όλων', + 'select_none' => 'επιλέξτε κανένα', 'select_placeholder' => 'παρακαλούμε επιλέξτε', 'insert_row' => 'Προσθήκη Σειράς', 'insert_row_below' => 'Προσθήκη Σειράς από Κάτω', diff --git a/modules/backend/lang/en/lang.php b/modules/backend/lang/en/lang.php index 2a56e609e3..0b816e1e51 100644 --- a/modules/backend/lang/en/lang.php +++ b/modules/backend/lang/en/lang.php @@ -293,8 +293,8 @@ 'preview_no_media_message' => 'There is no media selected.', 'preview_no_record_message' => 'There is no record selected.', 'select' => 'Select', - 'select_all' => 'all', - 'select_none' => 'none', + 'select_all' => 'Select all', + 'select_none' => 'Select none', 'select_placeholder' => 'please select', 'insert_row' => 'Insert Row', 'insert_row_below' => 'Insert Row Below', diff --git a/modules/backend/lang/es-ar/lang.php b/modules/backend/lang/es-ar/lang.php index 1bab0ad4ad..ec5d209938 100644 --- a/modules/backend/lang/es-ar/lang.php +++ b/modules/backend/lang/es-ar/lang.php @@ -161,8 +161,8 @@ 'behavior_not_ready' => 'Por favor compruebe que ha llamado a la funcion initForm() en el controlador.', 'preview_no_files_message' => 'Los archivos no fueron cargados.', 'select' => 'Seleccionar', - 'select_all' => 'Todo', - 'select_none' => 'Ninguno', + 'select_all' => 'seleccionar todo', + 'select_none' => 'no seleccionar ninguno', 'select_placeholder' => 'Seleccionar', 'insert_row' => 'Insertar fila', 'delete_row' => 'Eliminar fila', diff --git a/modules/backend/lang/es/lang.php b/modules/backend/lang/es/lang.php index 435b3d4c2e..a1ba3509ba 100644 --- a/modules/backend/lang/es/lang.php +++ b/modules/backend/lang/es/lang.php @@ -230,8 +230,8 @@ 'preview_no_files_message' => 'Los archivos no se han subido', 'preview_no_record_message' => 'No hay ningún registro seleccionado.', 'select' => 'Seleccionar', - 'select_all' => 'todos', - 'select_none' => 'ninguno', + 'select_all' => 'seleccionar todo', + 'select_none' => 'no seleccionar ninguno', 'select_placeholder' => 'por favor seleccione', 'insert_row' => 'Agregar Fila', 'insert_row_below' => 'Insertar fila debajo', diff --git a/modules/backend/lang/et/lang.php b/modules/backend/lang/et/lang.php index 9d1e0795c3..4f9ec469ed 100644 --- a/modules/backend/lang/et/lang.php +++ b/modules/backend/lang/et/lang.php @@ -245,8 +245,8 @@ 'preview_no_media_message' => 'Ühtegi meediafaili pole valitud.', 'preview_no_record_message' => 'Ühtegi kirjet pole valitud.', 'select' => 'Vali', - 'select_all' => 'kõik', - 'select_none' => 'mitte ükski', + 'select_all' => 'Vali kõik', + 'select_none' => 'vali ükski', 'select_placeholder' => 'palun vali', 'insert_row' => 'Lisa rida', 'insert_row_below' => 'Lisa rida alla', diff --git a/modules/backend/lang/fa/lang.php b/modules/backend/lang/fa/lang.php index e8c5f005a6..912bb6d551 100644 --- a/modules/backend/lang/fa/lang.php +++ b/modules/backend/lang/fa/lang.php @@ -263,8 +263,8 @@ 'preview_no_media_message' => 'رسانه ای انتخاب نشده است.', 'preview_no_record_message' => 'موردی انتخاب نشده است.', 'select' => 'انتخاب', - 'select_all' => 'همه', - 'select_none' => 'هیچ', + 'select_all' => 'انتخاب همه', + 'select_none' => 'هیچ کدام را انتخاب نکنید', 'select_placeholder' => 'لطفا انتخاب نمایید', 'insert_row' => 'افزودن سطر', 'insert_row_below' => 'افزودن سطر بعد از', diff --git a/modules/backend/lang/fi/lang.php b/modules/backend/lang/fi/lang.php index a2739683f3..cf46750f72 100644 --- a/modules/backend/lang/fi/lang.php +++ b/modules/backend/lang/fi/lang.php @@ -263,8 +263,8 @@ 'preview_no_media_message' => 'Ei valittua mediaa.', 'preview_no_record_message' => 'Ei valittua tietuetta.', 'select' => 'Valitse', - 'select_all' => 'kaikki', - 'select_none' => 'ei yhtään', + 'select_all' => 'Valitse kaikki', + 'select_none' => 'Älä valitse mitään', 'select_placeholder' => 'ole hyvä ja valitse', 'insert_row' => 'Lisää rivi', 'insert_row_below' => 'Lisää rivi alapuolelle', diff --git a/modules/backend/lang/fr/lang.php b/modules/backend/lang/fr/lang.php index 30bd7473c4..95269b20af 100644 --- a/modules/backend/lang/fr/lang.php +++ b/modules/backend/lang/fr/lang.php @@ -277,8 +277,8 @@ 'preview_no_media_message' => 'Aucun média sélectionné.', 'preview_no_record_message' => 'Il n’y a aucun enregistrement sélectionné.', 'select' => 'Sélectionner', - 'select_all' => 'tout', - 'select_none' => 'aucun', + 'select_all' => 'tout sélectionner', + 'select_none' => 'Ne rien sélectionner', 'select_placeholder' => 'Sélectionner une valeur', 'insert_row' => 'Insérer une ligne', 'insert_row_below' => 'Insérer une ligne dessous', diff --git a/modules/backend/lang/hu/lang.php b/modules/backend/lang/hu/lang.php index 407759a206..74f9e721f7 100644 --- a/modules/backend/lang/hu/lang.php +++ b/modules/backend/lang/hu/lang.php @@ -287,8 +287,8 @@ 'preview_no_media_message' => 'Nincs kiválasztva média.', 'preview_no_record_message' => 'Nincs kiválasztva mező.', 'select' => 'Kiválaszt', - 'select_all' => 'mind', - 'select_none' => 'egyik sem', + 'select_all' => 'mindet kiválaszt', + 'select_none' => 'ne válasszon egyet', 'select_placeholder' => 'válasszon', 'insert_row' => 'Sor beszúrása', 'insert_row_below' => 'Sor beszúrása alá', diff --git a/modules/backend/lang/id/lang.php b/modules/backend/lang/id/lang.php index 26a81cd147..b3e7ce4910 100644 --- a/modules/backend/lang/id/lang.php +++ b/modules/backend/lang/id/lang.php @@ -180,8 +180,8 @@ 'behavior_not_ready' => 'Behavior borang belum diinisialisasi, periksa apakah Anda telah memanggil initForm() pada controller Anda.', 'preview_no_files_message' => 'Berkas tidak terunggah', 'select' => 'Pilih', - 'select_all' => 'semua', - 'select_none' => 'tiada', + 'select_all' => 'Pilih Semua', + 'select_none' => 'Pilih tidak ada', 'select_placeholder' => 'silakan pilih', 'insert_row' => 'Sisipkan Baris', 'delete_row' => 'Hapus Baris', diff --git a/modules/backend/lang/it/lang.php b/modules/backend/lang/it/lang.php index a846331953..55b2b05189 100644 --- a/modules/backend/lang/it/lang.php +++ b/modules/backend/lang/it/lang.php @@ -230,8 +230,8 @@ 'preview_no_files_message' => 'Non ci sono file caricati.', 'preview_no_record_message' => 'Nessun record selezionato.', 'select' => 'Seleziona', - 'select_all' => 'tutti', - 'select_none' => 'nessuno', + 'select_all' => 'seleziona tutto', + 'select_none' => 'non selezionare niente', 'select_placeholder' => 'seleziona', 'insert_row' => 'Inserisci riga', 'insert_row_below' => 'Inserisci riga sotto', diff --git a/modules/backend/lang/ja/lang.php b/modules/backend/lang/ja/lang.php index e67ec5a8a0..affe10b25b 100644 --- a/modules/backend/lang/ja/lang.php +++ b/modules/backend/lang/ja/lang.php @@ -176,8 +176,8 @@ 'behavior_not_ready' => 'フォームビヘイビアーは初期化されていません。コントローラーでinitForm()を呼び出しているか確認してください。', 'preview_no_files_message' => 'ファイルはアップロードされません。', 'select' => '選択', - 'select_all' => 'すべて', - 'select_none' => 'なし', + 'select_all' => 'すべて選択', + 'select_none' => 'どれも選択しない', 'select_placeholder' => '選択してください', 'insert_row' => '行を挿入', 'delete_row' => '行を削除', diff --git a/modules/backend/lang/kr/lang.php b/modules/backend/lang/kr/lang.php index e18099611d..3aeec12507 100644 --- a/modules/backend/lang/kr/lang.php +++ b/modules/backend/lang/kr/lang.php @@ -244,8 +244,8 @@ 'preview_no_media_message' => '선택하신 미디어가 없습니다.', 'preview_no_record_message' => '선택하신 기록이 없습니다.', 'select' => '선택', - 'select_all' => '전체선택', - 'select_none' => '선택없음', + 'select_all' => '모두 선택', + 'select_none' => '없음을 선택하십시오', 'select_placeholder' => '선택해주세요', 'insert_row' => '행 추가', 'insert_row_below' => '아래 행 추가', diff --git a/modules/backend/lang/lt/lang.php b/modules/backend/lang/lt/lang.php index 94ad6c4463..251023e6ef 100644 --- a/modules/backend/lang/lt/lang.php +++ b/modules/backend/lang/lt/lang.php @@ -244,8 +244,8 @@ 'preview_no_files_message' => 'Nėra įkeltų failų.', 'preview_no_record_message' => 'Nėra pasirinktų įrašų.', 'select' => 'Pasirinkti', - 'select_all' => 'viską', - 'select_none' => 'nieko', + 'select_all' => 'pasirinkti viską', + 'select_none' => 'neišsirinkite nė vieno', 'select_placeholder' => 'prašome pasirinkti', 'insert_row' => 'Pridėti Eilutę', 'insert_row_below' => 'Pridėti Eilutę Žemiau', diff --git a/modules/backend/lang/lv/lang.php b/modules/backend/lang/lv/lang.php index 6342a91bd5..56e7d8e80e 100644 --- a/modules/backend/lang/lv/lang.php +++ b/modules/backend/lang/lv/lang.php @@ -202,8 +202,8 @@ 'preview_no_files_message' => 'Faili nav augšupielādēti', 'preview_no_record_message' => 'Nav izvēlētu ierakstu.', 'select' => 'Izvēlēties', - 'select_all' => 'visus', - 'select_none' => 'nevienu', + 'select_all' => 'izvēlēties visus', + 'select_none' => 'neizvēlēties nevienu', 'select_placeholder' => 'lūdzu izvēlieties', 'insert_row' => 'Ievietot rindu', 'insert_row_below' => 'Ievietot riendu zemāk', diff --git a/modules/backend/lang/nb-no/lang.php b/modules/backend/lang/nb-no/lang.php index 47f8d20091..177eaa2bac 100644 --- a/modules/backend/lang/nb-no/lang.php +++ b/modules/backend/lang/nb-no/lang.php @@ -239,8 +239,8 @@ 'preview_no_files_message' => 'Filer er ikke opplastet', 'preview_no_record_message' => 'Det er ingen valgte oppføringer.', 'select' => 'Velg', - 'select_all' => 'alle', - 'select_none' => 'ingen', + 'select_all' => 'Velg alle', + 'select_none' => 'Velg ingen', 'select_placeholder' => 'velg', 'insert_row' => 'Sett inn rad', 'insert_row_below' => 'Sett inn rad under', diff --git a/modules/backend/lang/nl/lang.php b/modules/backend/lang/nl/lang.php index 3f52b7723a..010fe77ba4 100644 --- a/modules/backend/lang/nl/lang.php +++ b/modules/backend/lang/nl/lang.php @@ -287,8 +287,8 @@ 'preview_no_media_message' => 'Er zijn geen media geselecteerd.', 'preview_no_record_message' => 'Er zijn geen records geselecteerd.', 'select' => 'Selecteer', - 'select_all' => 'alles', - 'select_none' => 'niets', + 'select_all' => 'selecteer alles', + 'select_none' => 'selecteer niets', 'select_placeholder' => 'selecteer', 'insert_row' => 'Rij invoegen', 'insert_row_below' => 'Rij onder invoegen', diff --git a/modules/backend/lang/pl/lang.php b/modules/backend/lang/pl/lang.php index 91fa42c7b3..dca9b7cdf1 100644 --- a/modules/backend/lang/pl/lang.php +++ b/modules/backend/lang/pl/lang.php @@ -253,8 +253,8 @@ 'preview_no_files_message' => 'Brak wgranych plików.', 'preview_no_record_message' => 'Brak zaznaczonych elementów.', 'select' => 'Zaznacz', - 'select_all' => 'wszystkie', - 'select_none' => 'żadne', + 'select_all' => 'Zaznacz wszystko', + 'select_none' => 'Wybierz brak', 'select_placeholder' => 'proszę zaznacz', 'insert_row' => 'Wstaw wiersz', 'insert_row_below' => 'Wstaw wiersz poniżej', diff --git a/modules/backend/lang/pt-br/lang.php b/modules/backend/lang/pt-br/lang.php index 2a9d2f2400..d8da04b89a 100644 --- a/modules/backend/lang/pt-br/lang.php +++ b/modules/backend/lang/pt-br/lang.php @@ -292,8 +292,8 @@ 'preview_no_media_message' => 'Não há mídia selecionada.', 'preview_no_record_message' => 'Nenhum registro selecionado.', 'select' => 'Selecionar', - 'select_all' => 'todos', - 'select_none' => 'nenhum', + 'select_all' => 'Selecionar tudo', + 'select_none' => 'Selecione nenhum', 'select_placeholder' => 'por favor, selecione', 'insert_row' => 'Inserir linha', 'insert_row_below' => 'Inserir linha abaixo', diff --git a/modules/backend/lang/pt-pt/lang.php b/modules/backend/lang/pt-pt/lang.php index 203d4edbbd..a0b8017324 100644 --- a/modules/backend/lang/pt-pt/lang.php +++ b/modules/backend/lang/pt-pt/lang.php @@ -245,8 +245,8 @@ 'preview_no_media_message' => 'Nenhum conteúdo selecionado.', 'preview_no_record_message' => 'Nenhum registo selecionado.', 'select' => 'Selecionar', - 'select_all' => 'todos', - 'select_none' => 'nenhum', + 'select_all' => 'Selecionar tudo', + 'select_none' => 'Selecione nenhum', 'select_placeholder' => 'por favor, selecione', 'insert_row' => 'Inserir linha', 'insert_row_below' => 'Inserir linha abaixo', diff --git a/modules/backend/lang/ro/lang.php b/modules/backend/lang/ro/lang.php index 8728f30cbb..294ffb075d 100644 --- a/modules/backend/lang/ro/lang.php +++ b/modules/backend/lang/ro/lang.php @@ -149,8 +149,8 @@ 'behavior_not_ready' => 'Setarile initiale ale formularului nu au fost definite, verificati existenta functiei initForm() in controller.', 'preview_no_files_message' => 'Fisierele nu au fost incarcate', 'select' => 'Selectare', - 'select_all' => 'toate', - 'select_none' => 'niciunul', + 'select_all' => 'Selectează tot', + 'select_none' => 'Selectați niciuna', ], 'relation' => [ 'missing_definition' => "Relatia nu contine definitii pentru campul ':field'.", diff --git a/modules/backend/lang/ru/lang.php b/modules/backend/lang/ru/lang.php index 040c8fdd3c..40daacacb7 100644 --- a/modules/backend/lang/ru/lang.php +++ b/modules/backend/lang/ru/lang.php @@ -269,8 +269,8 @@ 'preview_no_media_message' => 'Нет выбраного медиа.', 'preview_no_record_message' => 'Нет выбранных записей.', 'select' => 'Выбрать', - 'select_all' => 'все', - 'select_none' => 'ничего', + 'select_all' => 'выбрать все', + 'select_none' => 'выберите ни одного', 'select_placeholder' => 'Пожалуйста, выберите', 'insert_row' => 'Вставить строку', 'insert_row_below' => 'Вставить строку ниже', diff --git a/modules/backend/lang/sk/lang.php b/modules/backend/lang/sk/lang.php index f2dd887d90..56d9424c13 100644 --- a/modules/backend/lang/sk/lang.php +++ b/modules/backend/lang/sk/lang.php @@ -263,8 +263,8 @@ 'preview_no_media_message' => 'Žiadne médium nebolo vybrané.', 'preview_no_record_message' => 'Žiadny záznam nie je vybraný', 'select' => 'Vybrať', - 'select_all' => 'všetko', - 'select_none' => 'nič', + 'select_all' => 'vybrať všetko', + 'select_none' => 'nevyber nič', 'select_placeholder' => 'prosím vyberte', 'insert_row' => 'Vložiť riadok', 'insert_row_below' => 'Vložiť riadok pod', diff --git a/modules/backend/lang/sv/lang.php b/modules/backend/lang/sv/lang.php index c62992356a..6399be137c 100644 --- a/modules/backend/lang/sv/lang.php +++ b/modules/backend/lang/sv/lang.php @@ -193,8 +193,8 @@ 'preview_no_files_message' => 'Filen är inte uppladdad', 'preview_no_record_message' => 'Ingen rad är vald.', 'select' => 'Välj', - 'select_all' => 'alla', - 'select_none' => 'ingen', + 'select_all' => 'Välj alla', + 'select_none' => 'Välj ingen', 'select_placeholder' => 'Vänligen välj', 'insert_row' => 'Lägg till rad', 'delete_row' => 'Radera rad', diff --git a/modules/backend/lang/th/lang.php b/modules/backend/lang/th/lang.php index d9e9c1d09f..6dae203a45 100644 --- a/modules/backend/lang/th/lang.php +++ b/modules/backend/lang/th/lang.php @@ -273,8 +273,8 @@ 'preview_no_files_message' => 'ไม่มีไฟล์ถูกอัพโหลด', 'preview_no_media_message' => 'ไม่มีสื่อบันทึกที่ถูกเลือก', 'select' => 'เลือก', - 'select_all' => 'ทั้งหมด', - 'select_none' => 'ไม่มี', + 'select_all' => 'เลือกทั้งหมด', + 'select_none' => 'ไม่เลือกเลย', 'select_placeholder' => 'กรุณาเลือก', 'insert_row' => 'เพิ่มบรรทัด', 'insert_row_below' => 'เพิ่มบรรทัดด้านล่าง', diff --git a/modules/backend/lang/tr/lang.php b/modules/backend/lang/tr/lang.php index 8c61015499..781be07c61 100644 --- a/modules/backend/lang/tr/lang.php +++ b/modules/backend/lang/tr/lang.php @@ -277,8 +277,8 @@ 'preview_no_media_message' => 'Seçilmiş medya yok.', 'preview_no_record_message' => 'Seçili kayıt yok.', 'select' => 'Seç', - 'select_all' => 'tümü', - 'select_none' => 'hiçbiri', + 'select_all' => 'hepsini seç', + 'select_none' => 'hiçbir şey seçilmedi', 'select_placeholder' => 'lütfen seçin', 'insert_row' => 'Kayıt Ekle', 'insert_row_below' => 'Alt Satıra Kayıt Ekle', diff --git a/modules/backend/lang/uk/lang.php b/modules/backend/lang/uk/lang.php index 186e62d8cf..4b0a1cb027 100644 --- a/modules/backend/lang/uk/lang.php +++ b/modules/backend/lang/uk/lang.php @@ -262,8 +262,8 @@ 'preview_no_media_message' => 'Немає обраного файла.', 'preview_no_record_message' => 'Немає обраних записів.', 'select' => 'Обрати', - 'select_all' => 'всі', - 'select_none' => 'жоден', + 'select_all' => 'вибрати все', + 'select_none' => 'вибрати жоден', 'select_placeholder' => 'будь ласка, оберіть', 'insert_row' => 'Вставити рядок', 'insert_row_below' => 'Вставити рядок нижче', diff --git a/modules/backend/lang/vn/lang.php b/modules/backend/lang/vn/lang.php index 5b31171b46..7f4e9db884 100644 --- a/modules/backend/lang/vn/lang.php +++ b/modules/backend/lang/vn/lang.php @@ -263,8 +263,8 @@ 'preview_no_media_message' => 'Không có file media nào được chọn.', 'preview_no_record_message' => 'Không có bản ghi nào được chọn.', 'select' => 'Select', - 'select_all' => 'Tất cả', - 'select_none' => 'none', + 'select_all' => 'chọn tất cả', + 'select_none' => 'không chọn', 'select_placeholder' => 'Vui lòng lựa chọn', 'insert_row' => 'Thêm mới Row', 'insert_row_below' => 'Thêm Row dưới đây', diff --git a/modules/backend/lang/zh-cn/lang.php b/modules/backend/lang/zh-cn/lang.php index 17bafd8701..3753535ed7 100644 --- a/modules/backend/lang/zh-cn/lang.php +++ b/modules/backend/lang/zh-cn/lang.php @@ -287,8 +287,8 @@ 'preview_no_media_message' => '无选中媒体.', 'preview_no_record_message' => '无选择记录。', 'select' => '选择', - 'select_all' => '全部', - 'select_none' => '无', + 'select_all' => '全选', + 'select_none' => '选择无', 'select_placeholder' => '请选择', 'insert_row' => '插入行', 'insert_row_below' => '在下面插入行', diff --git a/modules/backend/lang/zh-tw/lang.php b/modules/backend/lang/zh-tw/lang.php index 2eb80615a8..35ab3510bc 100644 --- a/modules/backend/lang/zh-tw/lang.php +++ b/modules/backend/lang/zh-tw/lang.php @@ -181,8 +181,8 @@ 'behavior_not_ready' => '表單還沒初始化, 確保您調用了控制器中的 initForm()', 'preview_no_files_message' => '檔案沒有上傳', 'select' => '選擇', - 'select_all' => 'all', - 'select_none' => 'none', + 'select_all' => '全選', + 'select_none' => '選擇無', 'select_placeholder' => '請選擇', 'insert_row' => '插入行', 'delete_row' => '刪除行', diff --git a/modules/backend/widgets/form/partials/_field_checkboxlist.htm b/modules/backend/widgets/form/partials/_field_checkboxlist.htm index afabfcb889..2eab55016d 100644 --- a/modules/backend/widgets/form/partials/_field_checkboxlist.htm +++ b/modules/backend/widgets/form/partials/_field_checkboxlist.htm @@ -40,50 +40,58 @@
- - : - , - - - - - -
-
+
+
+ +
+
+ +
+
- +
- $option): ?> - getId().'_'.$index; - if (is_string($option)) $option = [$option]; - ?> -
- > + + +
+
+ - - -

- -
- + + + $option): ?> + getId().'_'.$index; + if (is_string($option)) $option = [$option]; + ?> +
+ > - + + +

+
-
- + + + +
+
+ + +
diff --git a/modules/system/assets/ui/less/form.base.less b/modules/system/assets/ui/less/form.base.less index ce08b8f0f2..00078238ae 100644 --- a/modules/system/assets/ui/less/form.base.less +++ b/modules/system/assets/ui/less/form.base.less @@ -197,7 +197,7 @@ input[type="date"] { display: block; min-height: @line-height-computed; // clear the floating input if there is no label text margin-top: 10px; - margin-bottom: 10px; + margin-bottom: 15px; padding-left: 20px; label { display: inline; diff --git a/modules/system/assets/ui/less/form.less b/modules/system/assets/ui/less/form.less index 38503f80e7..409cf07f23 100644 --- a/modules/system/assets/ui/less/form.less +++ b/modules/system/assets/ui/less/form.less @@ -316,7 +316,6 @@ } .field-checkboxlist:not(.is-scrollable) { - padding: 20px 20px 2px 20px; .border-radius(@border-radius-base); background: @color-form-checkboxlist-background; border: 1px solid @color-form-checkboxlist-border; @@ -332,6 +331,42 @@ } } +.field-checkboxlist { + .checkboxlist-controls { + padding: 15px 15px 0 15px; + border-bottom: 1px solid #e2e2e2; + color: @color-label; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -webkit-box-align: baseline; + -ms-flex-align: baseline; + align-items: baseline; + a { + margin-right: 15px; + margin-bottom: 15px; + text-decoration: none; + color: @color-label; + } + >div { + padding-right: 15px; + padding-bottom: 15px; + } + + .search-input-wrap { + margin-left: auto; + } + } +} + +.field-checkboxlist-container { + &:not(.is-scrollable) { + padding: 20px 20px 2px 20px; + } +} + .field-checkboxlist-scrollable { background: @color-form-checkboxlist-background; border: 1px solid @color-form-checkboxlist-border; diff --git a/modules/system/assets/ui/storm.css b/modules/system/assets/ui/storm.css index 600318f191..dc22ccfa50 100644 --- a/modules/system/assets/ui/storm.css +++ b/modules/system/assets/ui/storm.css @@ -3705,7 +3705,7 @@ input[type="search"] {-webkit-appearance:none} input[type="date"] {line-height:38px} .form-group {margin-bottom:15px} .radio, -.checkbox {display:block;min-height:20px;margin-top:10px;margin-bottom:10px;padding-left:20px} +.checkbox {display:block;min-height:20px;margin-top:10px;margin-bottom:15px;padding-left:20px} .radio label, .checkbox label {display:inline;font-weight:normal;cursor:pointer} .radio input[type="radio"], @@ -4236,8 +4236,13 @@ html.cssanimations .cursor-loading-indicator.hide {display:none} .field-textarea.size-large {min-height:200px} .field-textarea.size-huge {min-height:250px} .field-textarea.size-giant {min-height:350px} -.field-checkboxlist:not(.is-scrollable) {padding:20px 20px 2px 20px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;background:#fff;border:1px solid #e2e2e2} +.field-checkboxlist:not(.is-scrollable) {-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;background:#fff;border:1px solid #e2e2e2} .field-checkboxlist.is-scrollable small {color:#999} +.field-checkboxlist .checkboxlist-controls {padding:15px 15px 0;border-bottom:1px solid #e2e2e2;color:#2a3e51;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline} +.field-checkboxlist .checkboxlist-controls a {margin-right:15px;margin-bottom:15px;text-decoration:none;color:#2a3e51} +.field-checkboxlist .checkboxlist-controls > div {padding-right:15px;padding-bottom:15px} +.field-checkboxlist .checkboxlist-controls .search-input-wrap {margin-left: auto} +.field-checkboxlist-container:not(.is-scrollable) {padding: 20px 20px 2px 20px} .field-checkboxlist-scrollable {background:#fff;border:1px solid #e2e2e2;padding-left:15px;height:300px} .field-checkboxlist-scrollable .checkbox {margin-top:15px;margin-bottom:5px} .field-checkboxlist-scrollable .checkbox ~ .checkbox {margin-top:0} From 46318054b7ca33374f9c3d2f18a52b95ffd7c7fe Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Sat, 21 Sep 2019 12:36:31 +1000 Subject: [PATCH 026/157] Tidy up checkbox list - refs #4599 Also had to revert the 100vw improvement on tabs because it causes unnecessary scroll/drag activation. Also reverted change in form.base.less that had no reasoning. --- .../form/partials/_field_checkboxlist.htm | 12 ++-- modules/system/assets/ui/less/form.base.less | 2 +- modules/system/assets/ui/less/form.less | 57 ++++++++----------- modules/system/assets/ui/less/tab.less | 4 +- modules/system/assets/ui/storm.css | 16 +++--- 5 files changed, 42 insertions(+), 49 deletions(-) diff --git a/modules/backend/widgets/form/partials/_field_checkboxlist.htm b/modules/backend/widgets/form/partials/_field_checkboxlist.htm index 2eab55016d..a5dc947fcd 100644 --- a/modules/backend/widgets/form/partials/_field_checkboxlist.htm +++ b/modules/backend/widgets/form/partials/_field_checkboxlist.htm @@ -42,17 +42,21 @@ -
+
- +
diff --git a/modules/system/assets/ui/less/form.base.less b/modules/system/assets/ui/less/form.base.less index 00078238ae..ce08b8f0f2 100644 --- a/modules/system/assets/ui/less/form.base.less +++ b/modules/system/assets/ui/less/form.base.less @@ -197,7 +197,7 @@ input[type="date"] { display: block; min-height: @line-height-computed; // clear the floating input if there is no label text margin-top: 10px; - margin-bottom: 15px; + margin-bottom: 10px; padding-left: 20px; label { display: inline; diff --git a/modules/system/assets/ui/less/form.less b/modules/system/assets/ui/less/form.less index 409cf07f23..30bd6b0296 100644 --- a/modules/system/assets/ui/less/form.less +++ b/modules/system/assets/ui/less/form.less @@ -315,27 +315,18 @@ &.size-giant { min-height: @size-giant; } } -.field-checkboxlist:not(.is-scrollable) { - .border-radius(@border-radius-base); - background: @color-form-checkboxlist-background; - border: 1px solid @color-form-checkboxlist-border; - - //.checkbox:last-of-type { - // margin-bottom: 0; - //} -} +.field-checkboxlist { + &:not(.is-scrollable) { + .border-radius(@border-radius-base); + background: @color-form-checkboxlist-background; + border: 1px solid @color-form-checkboxlist-border; -.field-checkboxlist.is-scrollable { - small { - color: @text-muted; + .field-checkboxlist-inner { + padding: 20px 20px 2px 20px; + } } -} -.field-checkboxlist { .checkboxlist-controls { - padding: 15px 15px 0 15px; - border-bottom: 1px solid #e2e2e2; - color: @color-label; display: -webkit-box; display: -ms-flexbox; display: flex; @@ -344,28 +335,26 @@ -webkit-box-align: baseline; -ms-flex-align: baseline; align-items: baseline; - a { - margin-right: 15px; - margin-bottom: 15px; - text-decoration: none; - color: @color-label; - } - >div { - padding-right: 15px; - padding-bottom: 15px; - } + > div { + padding-bottom: 7px; + + > a { + font-size: 13px; + margin-right: 20px; + text-decoration: none; + > i { + color: @text-muted; + margin: 0 4px; + } - .search-input-wrap { - margin-left: auto; + &:hover > i { + color: @color-label; + } + } } } } -.field-checkboxlist-container { - &:not(.is-scrollable) { - padding: 20px 20px 2px 20px; - } -} .field-checkboxlist-scrollable { background: @color-form-checkboxlist-background; diff --git a/modules/system/assets/ui/less/tab.less b/modules/system/assets/ui/less/tab.less index 1be5efeac0..8ceeaee54d 100644 --- a/modules/system/assets/ui/less/tab.less +++ b/modules/system/assets/ui/less/tab.less @@ -112,7 +112,7 @@ padding-top: 7px; > span:not([class*="oc-icon"]) { margin-right: 8px; - } + } } } @@ -250,7 +250,7 @@ position: absolute; bottom: 0; height: 1px; - width: 100vw; + width: 100%; z-index: @zindex-tab - 1; content: ' '; border-bottom: 2px solid @color-tab-active-border; diff --git a/modules/system/assets/ui/storm.css b/modules/system/assets/ui/storm.css index dc22ccfa50..72422b225e 100644 --- a/modules/system/assets/ui/storm.css +++ b/modules/system/assets/ui/storm.css @@ -2872,7 +2872,7 @@ body.compact-container .control-breadcrumb {margin-top:0;margin-left:0;margin-ri .control-tabs.primary-tabs >div >div >ul.nav-tabs {position:relative;margin-left:0;margin-right:0} .control-tabs.primary-tabs >ul.nav-tabs:before, .control-tabs.primary-tabs >div >ul.nav-tabs:before, -.control-tabs.primary-tabs >div >div >ul.nav-tabs:before {position:absolute;bottom:0;height:1px;width:100vw;z-index:9;content:' ';border-bottom:2px solid #d0d0d0} +.control-tabs.primary-tabs >div >div >ul.nav-tabs:before {position:absolute;bottom:0;height:1px;width:100%;z-index:9;content:' ';border-bottom:2px solid #d0d0d0} .control-tabs.primary-tabs >ul.nav-tabs >li, .control-tabs.primary-tabs >div >ul.nav-tabs >li, .control-tabs.primary-tabs >div >div >ul.nav-tabs >li {padding-right:0;padding-left:0;margin-left:0;margin-right:-20px;background:transparent} @@ -3705,7 +3705,7 @@ input[type="search"] {-webkit-appearance:none} input[type="date"] {line-height:38px} .form-group {margin-bottom:15px} .radio, -.checkbox {display:block;min-height:20px;margin-top:10px;margin-bottom:15px;padding-left:20px} +.checkbox {display:block;min-height:20px;margin-top:10px;margin-bottom:10px;padding-left:20px} .radio label, .checkbox label {display:inline;font-weight:normal;cursor:pointer} .radio input[type="radio"], @@ -4237,12 +4237,12 @@ html.cssanimations .cursor-loading-indicator.hide {display:none} .field-textarea.size-huge {min-height:250px} .field-textarea.size-giant {min-height:350px} .field-checkboxlist:not(.is-scrollable) {-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;background:#fff;border:1px solid #e2e2e2} -.field-checkboxlist.is-scrollable small {color:#999} -.field-checkboxlist .checkboxlist-controls {padding:15px 15px 0;border-bottom:1px solid #e2e2e2;color:#2a3e51;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline} -.field-checkboxlist .checkboxlist-controls a {margin-right:15px;margin-bottom:15px;text-decoration:none;color:#2a3e51} -.field-checkboxlist .checkboxlist-controls > div {padding-right:15px;padding-bottom:15px} -.field-checkboxlist .checkboxlist-controls .search-input-wrap {margin-left: auto} -.field-checkboxlist-container:not(.is-scrollable) {padding: 20px 20px 2px 20px} +.field-checkboxlist:not(.is-scrollable) .field-checkboxlist-inner {padding:20px 20px 2px 20px} +.field-checkboxlist .checkboxlist-controls {display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline} +.field-checkboxlist .checkboxlist-controls >div {padding-bottom:7px} +.field-checkboxlist .checkboxlist-controls >div >a {font-size:13px;margin-right:20px;text-decoration:none} +.field-checkboxlist .checkboxlist-controls >div >a >i {color:#999;margin:0 4px} +.field-checkboxlist .checkboxlist-controls >div >a:hover >i {color:#2a3e51} .field-checkboxlist-scrollable {background:#fff;border:1px solid #e2e2e2;padding-left:15px;height:300px} .field-checkboxlist-scrollable .checkbox {margin-top:15px;margin-bottom:5px} .field-checkboxlist-scrollable .checkbox ~ .checkbox {margin-top:0} From e45a87071169b43c1c1e5d234f8fba04346e6369 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Sat, 21 Sep 2019 12:44:04 +1000 Subject: [PATCH 027/157] This stops tabnabbing apparently Refs #4550 Refs https://en.wikipedia.org/wiki/Tabnabbing --- modules/backend/layouts/_mainmenu.htm | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/backend/layouts/_mainmenu.htm b/modules/backend/layouts/_mainmenu.htm index 0577c2c7e5..3b934f2b3b 100644 --- a/modules/backend/layouts/_mainmenu.htm +++ b/modules/backend/layouts/_mainmenu.htm @@ -51,6 +51,7 @@ From 4b84b51f248010dce3db08a0c7608cdef348be9c Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Sat, 21 Sep 2019 13:12:49 +1000 Subject: [PATCH 028/157] Lazyload top navigation icons - refs #4562 --- modules/backend/assets/css/october.css | 2 +- modules/backend/assets/less/layout/mainmenu.less | 1 + modules/backend/layouts/_mainmenu.htm | 8 ++++++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/modules/backend/assets/css/october.css b/modules/backend/assets/css/october.css index 29ead2b350..fb572f7c55 100644 --- a/modules/backend/assets/css/october.css +++ b/modules/backend/assets/css/october.css @@ -685,7 +685,7 @@ nav#layout-mainmenu ul.mainmenu-toolbar li.mainmenu-preview a {position:relative nav#layout-mainmenu ul.mainmenu-toolbar li.mainmenu-account {margin-right:0} nav#layout-mainmenu ul.mainmenu-toolbar li.mainmenu-account >a {padding:0 15px 0 10px;font-size:13px;position:relative} nav#layout-mainmenu ul.mainmenu-toolbar li.mainmenu-account.highlight >a {z-index:600} -nav#layout-mainmenu ul.mainmenu-toolbar li.mainmenu-account img.account-avatar {width:45px} +nav#layout-mainmenu ul.mainmenu-toolbar li.mainmenu-account img.account-avatar {width:45px;height:45px} nav#layout-mainmenu ul.mainmenu-toolbar li.mainmenu-account .account-name {margin-right:15px} nav#layout-mainmenu ul.mainmenu-toolbar li.mainmenu-account ul {line-height:23px} html.svg nav#layout-mainmenu img.svg-icon, diff --git a/modules/backend/assets/less/layout/mainmenu.less b/modules/backend/assets/less/layout/mainmenu.less index 27b125c358..a1af75cc9d 100644 --- a/modules/backend/assets/less/layout/mainmenu.less +++ b/modules/backend/assets/less/layout/mainmenu.less @@ -214,6 +214,7 @@ nav#layout-mainmenu { img.account-avatar { width: 45px; + height: 45px; } .account-name { diff --git a/modules/backend/layouts/_mainmenu.htm b/modules/backend/layouts/_mainmenu.htm index 3b934f2b3b..bdcae757f9 100644 --- a/modules/backend/layouts/_mainmenu.htm +++ b/modules/backend/layouts/_mainmenu.htm @@ -24,7 +24,9 @@ iconSvg): ?> - + @@ -60,7 +62,9 @@ - +
diff --git a/modules/backend/controllers/userroles/update.htm b/modules/backend/controllers/userroles/update.htm index 7f1b977368..9a50815d93 100644 --- a/modules/backend/controllers/userroles/update.htm +++ b/modules/backend/controllers/userroles/update.htm @@ -36,11 +36,10 @@
From dd437e42d604b12813db1c559347921e5898e884 Mon Sep 17 00:00:00 2001 From: Ayumi Hamasaki <55155131+ayumihamasaki2019@users.noreply.github.com> Date: Fri, 27 Sep 2019 20:04:46 +0100 Subject: [PATCH 043/157] Update mustache.js to 2.3.2 (#4644) Credit to @ayumihamasaki2019 --- .../assets/ui/vendor/mustache/mustache.js | 224 ++++++++++-------- 1 file changed, 127 insertions(+), 97 deletions(-) diff --git a/modules/system/assets/ui/vendor/mustache/mustache.js b/modules/system/assets/ui/vendor/mustache/mustache.js index 344d65b860..e83c5f9c69 100644 --- a/modules/system/assets/ui/vendor/mustache/mustache.js +++ b/modules/system/assets/ui/vendor/mustache/mustache.js @@ -1,56 +1,76 @@ /*! * mustache.js - Logic-less {{mustache}} templates with JavaScript * http://github.com/janl/mustache.js + * version 2.3.2 */ -/*global define: false*/ +/*global define: false Mustache: true*/ -(function (global, factory) { - if (typeof exports === "object" && exports) { +(function defineMustache (global, factory) { + if (typeof exports === 'object' && exports && typeof exports.nodeName !== 'string') { factory(exports); // CommonJS - } else if (typeof define === "function" && define.amd) { + } else if (typeof define === 'function' && define.amd) { define(['exports'], factory); // AMD } else { - factory(global.Mustache = {}); // diff --git a/modules/backend/layouts/auth.htm b/modules/backend/layouts/auth.htm index e28b2e555e..5b66888aa7 100644 --- a/modules/backend/layouts/auth.htm +++ b/modules/backend/layouts/auth.htm @@ -41,17 +41,18 @@ From a6f9b5b3460b6325d4626c7abc146ec6339701cb Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Wed, 9 Oct 2019 11:51:06 -0600 Subject: [PATCH 066/157] Provide system.assets.beforeAddAsset event to modify asset attributes Fixes octobercms/october#4611 (when combined with a PR to https://github.com/heathdutton/cloudflare) Related: octobercms/october#4092, octobercms/october#3841, octobercms/october#3839 --- modules/backend/formwidgets/FileUpload.php | 5 +- modules/backend/widgets/Form.php | 5 +- modules/system/traits/AssetMaker.php | 72 +++++++++++++++++----- 3 files changed, 58 insertions(+), 24 deletions(-) diff --git a/modules/backend/formwidgets/FileUpload.php b/modules/backend/formwidgets/FileUpload.php index 0a8f5d1ba9..89e2d3e574 100644 --- a/modules/backend/formwidgets/FileUpload.php +++ b/modules/backend/formwidgets/FileUpload.php @@ -407,10 +407,7 @@ public function onSaveAttachmentConfig() protected function loadAssets() { $this->addCss('css/fileupload.css', 'core'); - $this->addJs('js/fileupload.js', [ - 'build' => 'core', - 'cache' => 'false' - ]); + $this->addJs('js/fileupload.js', 'core'); } /** diff --git a/modules/backend/widgets/Form.php b/modules/backend/widgets/Form.php index 17e630b96c..c16e75bdd3 100644 --- a/modules/backend/widgets/Form.php +++ b/modules/backend/widgets/Form.php @@ -159,10 +159,7 @@ public function bindToController() */ protected function loadAssets() { - $this->addJs('js/october.form.js', [ - 'build' => 'core', - 'cache' => 'false' - ]); + $this->addJs('js/october.form.js', 'core'); } /** diff --git a/modules/system/traits/AssetMaker.php b/modules/system/traits/AssetMaker.php index 673e535967..4918872e71 100644 --- a/modules/system/traits/AssetMaker.php +++ b/modules/system/traits/AssetMaker.php @@ -3,6 +3,7 @@ use Url; use Html; use File; +use Event; use System\Models\Parameter; use System\Models\PluginVersion; use System\Classes\CombineAssets; @@ -16,7 +17,6 @@ */ trait AssetMaker { - /** * @var array Collection of assets to display in the layout. */ @@ -127,16 +127,7 @@ public function addJs($name, $attributes = []) $jsPath = $this->getAssetScheme($jsPath); - // Prevent CloudFlare's Rocket Loader from breaking stuff - // @see octobercms/october#4092, octobercms/october#3841, octobercms/october#3839 - if (isset($attributes['cache']) && $attributes['cache'] == 'false') { - $attributes['data-cfasync'] = 'false'; - unset($attributes['cache']); - } - - if (!in_array($jsPath, $this->assets['js'])) { - $this->assets['js'][] = ['path' => $jsPath, 'attributes' => $attributes]; - } + $this->addAsset('js', $jsPath, $attributes); } /** @@ -164,9 +155,7 @@ public function addCss($name, $attributes = []) $cssPath = $this->getAssetScheme($cssPath); - if (!in_array($cssPath, $this->assets['css'])) { - $this->assets['css'][] = ['path' => $cssPath, 'attributes' => $attributes]; - } + $this->addAsset('css', $cssPath, $attributes); } /** @@ -190,8 +179,59 @@ public function addRss($name, $attributes = []) $rssPath = $this->getAssetScheme($rssPath); - if (!in_array($rssPath, $this->assets['rss'])) { - $this->assets['rss'][] = ['path' => $rssPath, 'attributes' => $attributes]; + $this->addAsset('rss', $rssPath, $attributes); + } + + /** + * Adds the provided asset to the internal asset collections + * + * @param string $type The type of the asset: 'js' || 'css' || 'rss' + * @param string $path The path to the asset + * @param array $attributes The attributes for the asset + */ + protected function addAsset(string $type, string $path, array $attributes) + { + if (!in_array($path, $this->assets[$type])) { + /** + * @event system.assets.beforeAddAsset + * Provides an opportunity to inspect or modify an asset. + * + * The parameters provided are: + * string `$type`: The type of the asset being added + * string `$path`: The path to the asset being added + * array `$attributes`: The array of attributes for the asset being added. + * + * All the parameters are provided by reference for modification. + * This event is also a halting event, so returning false will prevent the + * current asset from being added. Note that duplicates are filtered out + * before the event is fired. + * + * Example usage: + * + * Event::listen('system.assets.beforeAddAsset', function (string $type, string $path, array $attributes) { + * if (in_array($path, $blockedAssets)) { + * return false; + * } + * }); + * + * Or + * + * $this->bindEvent('assets.beforeAddAsset', function (string $type, string $path, array $attributes) { + * $attributes['special_cdn_flag'] = false; + * }); + * + */ + if ( + // Fire local event if exists + ( + method_exists($this, 'fireEvent') && + ($this->fireEvent('assets.beforeAddAsset', [&$type, &$path, &$attributes], true) !== false) + ) && + // Fire global event + (Event::fire('system.assets.beforeAddAsset', [&$type, &$path, &$attributes], true) !== false) + ) { + $this->assets[$type][] = ['path' => $path, 'attributes' => $attributes]; + } } } From 104a92bba3ff1e5b263c04c8ec474d8195f7c670 Mon Sep 17 00:00:00 2001 From: Samuell Date: Thu, 10 Oct 2019 00:41:53 +0200 Subject: [PATCH 067/157] Add permission support for fields, columns and filter scopes (#4520) Credit to @Samuell1. Fixes #1837. --- composer.json | 2 + modules/backend/widgets/Filter.php | 9 ++ modules/backend/widgets/Form.php | 7 + modules/backend/widgets/Lists.php | 13 +- tests/PluginTestCase.php | 12 +- tests/TestCase.php | 3 +- .../concerns/InteractsWithAuthentication.php | 149 ++++++++++++++++++ tests/fixtures/backend/models/UserFixture.php | 66 ++++++++ tests/unit/backend/widgets/FilterTest.php | 139 ++++++++++++++++ tests/unit/backend/widgets/FormTest.php | 115 +++++++++++++- tests/unit/backend/widgets/ListsTest.php | 140 ++++++++++++++++ 11 files changed, 650 insertions(+), 5 deletions(-) create mode 100644 tests/concerns/InteractsWithAuthentication.php create mode 100644 tests/fixtures/backend/models/UserFixture.php create mode 100644 tests/unit/backend/widgets/FilterTest.php create mode 100644 tests/unit/backend/widgets/ListsTest.php diff --git a/composer.json b/composer.json index 2050781e1c..e08f1cdde6 100644 --- a/composer.json +++ b/composer.json @@ -51,6 +51,8 @@ }, "autoload-dev": { "classmap": [ + "tests/concerns/InteractsWithAuthentication.php", + "tests/fixtures/backend/models/UserFixture.php", "tests/TestCase.php", "tests/UiTestCase.php", "tests/PluginTestCase.php" diff --git a/modules/backend/widgets/Filter.php b/modules/backend/widgets/Filter.php index 54789b9a3d..5deb972109 100644 --- a/modules/backend/widgets/Filter.php +++ b/modules/backend/widgets/Filter.php @@ -9,6 +9,7 @@ use Backend\Classes\WidgetBase; use Backend\Classes\FilterScope; use ApplicationException; +use BackendAuth; /** * Filter Widget @@ -559,6 +560,14 @@ protected function defineFilterScopes() public function addScopes(array $scopes) { foreach ($scopes as $name => $config) { + /* + * Check if user has permissions to show this filter + */ + $permissions = array_get($config, 'permissions'); + if (!empty($permissions) && !BackendAuth::getUser()->hasAccess($permissions, false)) { + continue; + } + $scopeObj = $this->makeFilterScope($name, $config); /* diff --git a/modules/backend/widgets/Form.php b/modules/backend/widgets/Form.php index c16e75bdd3..ce42ad24b4 100644 --- a/modules/backend/widgets/Form.php +++ b/modules/backend/widgets/Form.php @@ -11,6 +11,7 @@ use October\Rain\Html\Helper as HtmlHelper; use ApplicationException; use Exception; +use BackendAuth; /** * Form Widget @@ -682,6 +683,12 @@ protected function processAutoSpan($fields) public function addFields(array $fields, $addToArea = null) { foreach ($fields as $name => $config) { + // Check if user has permissions to show this field + $permissions = array_get($config, 'permissions'); + if (!empty($permissions) && !BackendAuth::getUser()->hasAccess($permissions, false)) { + continue; + } + $fieldObj = $this->makeFormField($name, $config); $fieldTab = is_array($config) ? array_get($config, 'tab') : null; diff --git a/modules/backend/widgets/Lists.php b/modules/backend/widgets/Lists.php index 6fddd5ca34..17d45631ff 100644 --- a/modules/backend/widgets/Lists.php +++ b/modules/backend/widgets/Lists.php @@ -14,6 +14,7 @@ use Backend\Classes\WidgetBase; use October\Rain\Database\Model; use ApplicationException; +use BackendAuth; /** * List Widget @@ -709,6 +710,10 @@ public function getColumns() */ public function getColumn($column) { + if (!isset($this->allColumns[$column])) { + throw new ApplicationException('No definition for column ' . $column); + } + return $this->allColumns[$column]; } @@ -852,6 +857,12 @@ public function addColumns(array $columns) * Build a final collection of list column objects */ foreach ($columns as $columnName => $config) { + // Check if user has permissions to show this column + $permissions = array_get($config, 'permissions'); + if (!empty($permissions) && !BackendAuth::getUser()->hasAccess($permissions, false)) { + continue; + } + $this->allColumns[$columnName] = $this->makeListColumn($columnName, $config); } } @@ -1150,7 +1161,7 @@ protected function evalCustomListType($type, $record, $column, $value) return call_user_func_array($callback, [$value, $column, $record]); } } - + $customMessage = ''; if ($type === 'relation') { $customMessage = 'Type: relation is not supported, instead use the relation property to specify a relationship to pull the value from and set the type to the type of the value expected.'; diff --git a/tests/PluginTestCase.php b/tests/PluginTestCase.php index 9689c87903..6618b17e0a 100644 --- a/tests/PluginTestCase.php +++ b/tests/PluginTestCase.php @@ -1,11 +1,15 @@ setDefaultDriver('array'); $app->setLocale('en'); + $app->singleton('auth', function ($app) { + $app['auth.loaded'] = true; + + return AuthManager::instance(); + }); + /* * Store database in memory by default, if not specified otherwise */ diff --git a/tests/TestCase.php b/tests/TestCase.php index ee25a6f429..062f670621 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -1,8 +1,6 @@ make('Illuminate\Contracts\Console\Kernel')->bootstrap(); $app['cache']->setDefaultDriver('array'); diff --git a/tests/concerns/InteractsWithAuthentication.php b/tests/concerns/InteractsWithAuthentication.php new file mode 100644 index 0000000000..a7950f2304 --- /dev/null +++ b/tests/concerns/InteractsWithAuthentication.php @@ -0,0 +1,149 @@ +be($user, $driver); + + return $this; + } + + /** + * Set the currently logged in user for the application. + * + * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @param string|null $driver + * @return void + */ + public function be(UserContract $user, $driver = null) + { + $this->app['auth']->setUser($user); + } + + /** + * Assert that the user is authenticated. + * + * @param string|null $guard + * @return $this + */ + public function assertAuthenticated($guard = null) + { + $this->assertTrue($this->isAuthenticated($guard), 'The user is not authenticated'); + + return $this; + } + + /** + * Assert that the user is not authenticated. + * + * @param string|null $guard + * @return $this + */ + public function assertGuest($guard = null) + { + $this->assertFalse($this->isAuthenticated($guard), 'The user is authenticated'); + + return $this; + } + + /** + * Return true if the user is authenticated, false otherwise. + * + * @param string|null $guard + * @return bool + */ + protected function isAuthenticated($guard = null) + { + return $this->app->make('auth')->guard($guard)->check(); + } + + /** + * Assert that the user is authenticated as the given user. + * + * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @param string|null $guard + * @return $this + */ + public function assertAuthenticatedAs($user, $guard = null) + { + $expected = $this->app->make('auth')->guard($guard)->user(); + + $this->assertNotNull($expected, 'The current user is not authenticated.'); + + $this->assertInstanceOf( + get_class($expected), + $user, + 'The currently authenticated user is not who was expected' + ); + + $this->assertSame( + $expected->getAuthIdentifier(), + $user->getAuthIdentifier(), + 'The currently authenticated user is not who was expected' + ); + + return $this; + } + + /** + * Assert that the given credentials are valid. + * + * @param array $credentials + * @param string|null $guard + * @return $this + */ + public function assertCredentials(array $credentials, $guard = null) + { + $this->assertTrue( + $this->hasCredentials($credentials, $guard), + 'The given credentials are invalid.' + ); + + return $this; + } + + /** + * Assert that the given credentials are invalid. + * + * @param array $credentials + * @param string|null $guard + * @return $this + */ + public function assertInvalidCredentials(array $credentials, $guard = null) + { + $this->assertFalse( + $this->hasCredentials($credentials, $guard), + 'The given credentials are valid.' + ); + + return $this; + } + + /** + * Return true if the credentials are valid, false otherwise. + * + * @param array $credentials + * @param string|null $guard + * @return bool + */ + protected function hasCredentials(array $credentials, $guard = null) + { + $provider = $this->app->make('auth')->guard($guard)->getProvider(); + + $user = $provider->retrieveByCredentials($credentials); + + return $user && $provider->validateCredentials($user, $credentials); + } +} diff --git a/tests/fixtures/backend/models/UserFixture.php b/tests/fixtures/backend/models/UserFixture.php new file mode 100644 index 0000000000..a444cd5972 --- /dev/null +++ b/tests/fixtures/backend/models/UserFixture.php @@ -0,0 +1,66 @@ +fill([ + 'first_name' => 'Test', + 'last_name' => 'User', + 'login' => 'testuser', + 'email' => 'testuser@test.com', + 'password' => '', + 'activation_code' => null, + 'persist_code' => null, + 'reset_password_code' => null, + 'permissions' => null, + 'is_activated' => true, + 'role_id' => null, + 'activated_at' => null, + 'last_login' => '2019-09-27 12:00:00', + 'created_at' => '2019-09-27 12:00:00', + 'updated_at' => '2019-09-27 12:00:00', + 'deleted_at' => null, + 'is_superuser' => false + ]); + } + + public function asSuperUser() + { + $this->setAttribute('is_superuser', true); + + return $this; + } + + public function asDeletedUser() + { + $this->setAttribute('deleted_at', date('Y-m-d H:i:s')); + + return $this; + } + + public function withPermission($permission, bool $granted = true) + { + $currentPermissions = $this->getAttribute('permissions'); + + if (is_string($permission)) { + $permission = [ + $permission => (int) $granted + ]; + } + + if (is_array($currentPermissions)) { + $this->setAttribute('permissions', array_replace($currentPermissions, $permission)); + } else { + $this->setAttribute('permissions', $permission); + } + + return $this; + } +} diff --git a/tests/unit/backend/widgets/FilterTest.php b/tests/unit/backend/widgets/FilterTest.php new file mode 100644 index 0000000000..05d0f0d787 --- /dev/null +++ b/tests/unit/backend/widgets/FilterTest.php @@ -0,0 +1,139 @@ +actingAs($user); + + $filter = $this->restrictedFilterFixture(); + $filter->render(); + + $this->assertNotNull($filter->getScope('id')); + + // Expect an exception + $this->expectException(ApplicationException::class); + $this->expectExceptionMessage('No definition for scope email'); + $scope = $filter->getScope('email'); + } + + public function testRestrictedScopeWithUserWithWrongPermissions() + { + $user = new UserFixture; + $this->actingAs($user->withPermission('test.wrong_permission', true)); + + $filter = $this->restrictedFilterFixture(); + $filter->render(); + + $this->assertNotNull($filter->getScope('id')); + + // Expect an exception + $this->expectException(ApplicationException::class); + $this->expectExceptionMessage('No definition for scope email'); + $scope = $filter->getScope('email'); + } + + public function testRestrictedScopeWithUserWithRightPermissions() + { + $user = new UserFixture; + $this->actingAs($user->withPermission('test.access_field', true)); + + $filter = $this->restrictedFilterFixture(); + $filter->render(); + + $this->assertNotNull($filter->getScope('id')); + $this->assertNotNull($filter->getScope('email')); + } + + public function testRestrictedScopeWithUserWithRightWildcardPermissions() + { + $user = new UserFixture; + $this->actingAs($user->withPermission('test.access_field', true)); + + $filter = new Filter(null, [ + 'model' => new User, + 'arrayName' => 'array', + 'scopes' => [ + 'id' => [ + 'type' => 'text', + 'label' => 'ID' + ], + 'email' => [ + 'type' => 'text', + 'label' => 'Email', + 'permission' => 'test.*' + ] + ] + ]); + $filter->render(); + + $this->assertNotNull($filter->getScope('id')); + $this->assertNotNull($filter->getScope('email')); + } + + public function testRestrictedScopeWithSuperuser() + { + $user = new UserFixture; + $this->actingAs($user->asSuperUser()); + + $filter = $this->restrictedFilterFixture(); + $filter->render(); + + $this->assertNotNull($filter->getScope('id')); + $this->assertNotNull($filter->getScope('email')); + } + + public function testRestrictedScopeSinglePermissionWithUserWithWrongPermissions() + { + $user = new UserFixture; + $this->actingAs($user->withPermission('test.wrong_permission', true)); + + $filter = $this->restrictedFilterFixture(true); + $filter->render(); + + $this->assertNotNull($filter->getScope('id')); + + // Expect an exception + $this->expectException(ApplicationException::class); + $this->expectExceptionMessage('No definition for scope email'); + $scope = $filter->getScope('email'); + } + + public function testRestrictedScopeSinglePermissionWithUserWithRightPermissions() + { + $user = new UserFixture; + $this->actingAs($user->withPermission('test.access_field', true)); + + $filter = $this->restrictedFilterFixture(true); + $filter->render(); + + $this->assertNotNull($filter->getScope('id')); + $this->assertNotNull($filter->getScope('email')); + } + + protected function restrictedFilterFixture(bool $singlePermission = false) + { + return new Filter(null, [ + 'model' => new User, + 'arrayName' => 'array', + 'scopes' => [ + 'id' => [ + 'type' => 'text', + 'label' => 'ID' + ], + 'email' => [ + 'type' => 'text', + 'label' => 'Email', + 'permissions' => ($singlePermission) ? 'test.access_field' : [ + 'test.access_field' + ] + ] + ] + ]); + } +} diff --git a/tests/unit/backend/widgets/FormTest.php b/tests/unit/backend/widgets/FormTest.php index 8fdaa7e4cf..d373a1d860 100644 --- a/tests/unit/backend/widgets/FormTest.php +++ b/tests/unit/backend/widgets/FormTest.php @@ -2,14 +2,106 @@ use Backend\Widgets\Form; use Illuminate\Database\Eloquent\Model; +use October\Tests\Fixtures\Backend\Models\UserFixture; class FormTestModel extends Model { } -class FormTest extends TestCase +class FormTest extends PluginTestCase { + public function testRestrictedFieldWithUserWithNoPermissions() + { + $user = new UserFixture; + $this->actingAs($user); + + $form = $this->restrictedFormFixture(); + + $form->render(); + $this->assertNull($form->getField('testRestricted')); + } + + public function testRestrictedFieldWithUserWithWrongPermissions() + { + $user = new UserFixture; + $this->actingAs($user->withPermission('test.wrong_permission', true)); + + $form = $this->restrictedFormFixture(); + + $form->render(); + $this->assertNull($form->getField('testRestricted')); + } + + public function testRestrictedFieldWithUserWithRightPermissions() + { + $user = new UserFixture; + $this->actingAs($user->withPermission('test.access_field', true)); + + $form = $this->restrictedFormFixture(); + + $form->render(); + $this->assertNotNull($form->getField('testRestricted')); + } + + public function testRestrictedFieldWithUserWithRightWildcardPermissions() + { + $user = new UserFixture; + $this->actingAs($user->withPermission('test.access_field', true)); + + $form = new Form(null, [ + 'model' => new FormTestModel, + 'arrayName' => 'array', + 'fields' => [ + 'testField' => [ + 'type' => 'text', + 'label' => 'Test 1' + ], + 'testRestricted' => [ + 'type' => 'text', + 'label' => 'Test 2', + 'permission' => 'test.*' + ] + ] + ]); + + $form->render(); + $this->assertNotNull($form->getField('testRestricted')); + } + + public function testRestrictedFieldWithSuperuser() + { + $user = new UserFixture; + $this->actingAs($user->asSuperUser()); + + $form = $this->restrictedFormFixture(); + + $form->render(); + $this->assertNotNull($form->getField('testRestricted')); + } + + public function testRestrictedFieldSinglePermissionWithUserWithWrongPermissions() + { + $user = new UserFixture; + $this->actingAs($user->withPermission('test.wrong_permission', true)); + + $form = $this->restrictedFormFixture(true); + + $form->render(); + $this->assertNull($form->getField('testRestricted')); + } + + public function testRestrictedFieldSinglePermissionWithUserWithRightPermissions() + { + $user = new UserFixture; + $this->actingAs($user->withPermission('test.access_field', true)); + + $form = $this->restrictedFormFixture(true); + + $form->render(); + $this->assertNotNull($form->getField('testRestricted')); + } + public function testCheckboxlistTrigger() { $form = new Form(null, [ @@ -38,4 +130,25 @@ public function testCheckboxlistTrigger() $attributes = $form->getField('triggered')->getAttributes('container', false); $this->assertEquals('[name="array[trigger][]"]', array_get($attributes, 'data-trigger')); } + + protected function restrictedFormFixture(bool $singlePermission = false) + { + return new Form(null, [ + 'model' => new FormTestModel, + 'arrayName' => 'array', + 'fields' => [ + 'testField' => [ + 'type' => 'text', + 'label' => 'Test 1' + ], + 'testRestricted' => [ + 'type' => 'text', + 'label' => 'Test 2', + 'permissions' => ($singlePermission) ? 'test.access_field' : [ + 'test.access_field' + ] + ] + ] + ]); + } } diff --git a/tests/unit/backend/widgets/ListsTest.php b/tests/unit/backend/widgets/ListsTest.php new file mode 100644 index 0000000000..e74aa877d4 --- /dev/null +++ b/tests/unit/backend/widgets/ListsTest.php @@ -0,0 +1,140 @@ +actingAs($user); + + $list = $this->restrictedListsFixture(); + $list->render(); + + $this->assertNotNull($list->getColumn('id')); + + // Expect an exception + $this->expectException(ApplicationException::class); + $this->expectExceptionMessage('No definition for column email'); + $column = $list->getColumn('email'); + } + + public function testRestrictedColumnWithUserWithWrongPermissions() + { + $user = new UserFixture; + $this->actingAs($user->withPermission('test.wrong_permission', true)); + + $list = $this->restrictedListsFixture(); + $list->render(); + + $this->assertNotNull($list->getColumn('id')); + + // Expect an exception + $this->expectException(ApplicationException::class); + $this->expectExceptionMessage('No definition for column email'); + $column = $list->getColumn('email'); + } + + public function testRestrictedColumnWithUserWithRightPermissions() + { + $user = new UserFixture; + $this->actingAs($user->withPermission('test.access_field', true)); + + $list = $this->restrictedListsFixture(); + $list->render(); + + $this->assertNotNull($list->getColumn('id')); + $this->assertNotNull($list->getColumn('email')); + } + + public function testRestrictedColumnWithUserWithRightWildcardPermissions() + { + $user = new UserFixture; + $this->actingAs($user->withPermission('test.access_field', true)); + + $list = new Lists(null, [ + 'model' => new User, + 'arrayName' => 'array', + 'columns' => [ + 'id' => [ + 'type' => 'text', + 'label' => 'ID' + ], + 'email' => [ + 'type' => 'text', + 'label' => 'Email', + 'permission' => 'test.*' + ] + ] + ]); + $list->render(); + + $this->assertNotNull($list->getColumn('id')); + $this->assertNotNull($list->getColumn('email')); + } + + public function testRestrictedColumnWithSuperuser() + { + $user = new UserFixture; + $this->actingAs($user->asSuperUser()); + + $list = $this->restrictedListsFixture(); + $list->render(); + + $this->assertNotNull($list->getColumn('id')); + $this->assertNotNull($list->getColumn('email')); + } + + public function testRestrictedColumnSinglePermissionWithUserWithWrongPermissions() + { + $user = new UserFixture; + $this->actingAs($user->withPermission('test.wrong_permission', true)); + + $list = $this->restrictedListsFixture(true); + $list->render(); + + $this->assertNotNull($list->getColumn('id')); + + // Expect an exception + $this->expectException(ApplicationException::class); + $this->expectExceptionMessage('No definition for column email'); + $column = $list->getColumn('email'); + } + + public function testRestrictedColumnSinglePermissionWithUserWithRightPermissions() + { + $user = new UserFixture; + $this->actingAs($user->withPermission('test.access_field', true)); + + $list = $this->restrictedListsFixture(true); + $list->render(); + + $this->assertNotNull($list->getColumn('id')); + $this->assertNotNull($list->getColumn('email')); + } + + protected function restrictedListsFixture(bool $singlePermission = false) + { + return new Lists(null, [ + 'model' => new User, + 'arrayName' => 'array', + 'columns' => [ + 'id' => [ + 'type' => 'text', + 'label' => 'ID' + ], + 'email' => [ + 'type' => 'text', + 'label' => 'Email', + 'permissions' => ($singlePermission) ? 'test.access_field' : [ + 'test.access_field' + ] + ] + ] + ]); + } +} From 46d3a1a63ceb1662389546e1173471fd0651ada7 Mon Sep 17 00:00:00 2001 From: nameewgeniy Date: Fri, 11 Oct 2019 14:59:42 +0300 Subject: [PATCH 068/157] Update ru/validation.php (#4687) Credit to @nameewgeniy --- modules/system/lang/ru/validation.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/system/lang/ru/validation.php b/modules/system/lang/ru/validation.php index f33856dbee..6ba1cc79fa 100644 --- a/modules/system/lang/ru/validation.php +++ b/modules/system/lang/ru/validation.php @@ -40,7 +40,7 @@ 'dimensions' => 'The :attribute has invalid image dimensions.', 'distinct' => 'The :attribute field has a duplicate value.', "email" => "Поле :attribute имеет ошибочный формат.", - "exists" => "Выбранное значение для :attribute уже существует.", + "exists" => "Выбранное значение для :attribute отсутствует.", 'file' => 'The :attribute must be a file.', 'filled' => 'The :attribute field must have a value.', "image" => "Поле :attribute должно быть изображением.", From e453ba615f0d202a39d96096d9675adf18c9297c Mon Sep 17 00:00:00 2001 From: 36864 <36864@users.noreply.github.com> Date: Fri, 11 Oct 2019 16:47:17 +0100 Subject: [PATCH 069/157] Improve Portuguese translation (#4689) Credit to @36864 --- modules/backend/lang/pt-pt/lang.php | 188 +++++++++++++++++++--------- 1 file changed, 127 insertions(+), 61 deletions(-) diff --git a/modules/backend/lang/pt-pt/lang.php b/modules/backend/lang/pt-pt/lang.php index 8cbbf37837..9c1b46da3f 100644 --- a/modules/backend/lang/pt-pt/lang.php +++ b/modules/backend/lang/pt-pt/lang.php @@ -3,11 +3,13 @@ return [ 'auth' => [ 'title' => 'Área Administrativa', + 'invalid_login' => 'As credenciais que introduziu não são válidas. Por favor verifique os seus dados e tente novamente.', ], 'field' => [ 'invalid_type' => 'Invalid field type used :type.', 'options_method_invalid_model' => "O atributo ':field' não é resolvido para um modelo válidol. Tente especificar o método de opções para a classe de modelo :model explicitamente.", - 'options_method_not_exists' => "A classe de modelo :model deve definir um método :method() retornando opções para o campo de formulário ':field'." + 'options_method_not_exists' => "A classe de modelo :model deve definir um método :method() que retorne opções para o campo de formulário ':field'.", + 'colors_method_not_exists' => "A classe de modelo :model deve definir um método :method() que retorne códigos de côr hexadecimais html para o campo de formulário':field'.", ], 'widget' => [ 'not_registered' => 'Uma classe de widget com o nome ":name" não foi registada', @@ -15,6 +17,11 @@ ], 'page' => [ 'untitled' => 'Sem título', + '404' => [ + 'label' => 'Página não encontrada', + 'help' => "Por muito que procuremos, o URL pedido não existe. Talvez esteja à procura de outra coisa?", + 'back_link' => 'Voltar à página anterior', + ], 'access_denied' => [ 'label' => 'Acesso negado', 'help' => 'Não tem as permissões necessárias para visualizar esta página.', @@ -23,19 +30,32 @@ 'no_database' => [ 'label' => 'Base de dados não existente', 'help' => "Uma base de dados é necessária para acesso ao back-end. Verifique se a base dados se encontra configurada e migrada antes de tentar novamente.", - 'cms_link' => 'Regressar á página inicial' + 'cms_link' => 'Regressar á página inicial', ], ], 'partial' => [ - 'not_found_name' => 'O bloco ":name" não foi encontrado.', + 'not_found_name' => 'O bloco parcial ":name" não foi encontrado.', + 'invalid_name' => 'Nome de bloco parcial inválido: :name.', + ], + 'ajax_handler' => [ + 'invalid_name' => 'Nome de processador AJAX inválido: :name.', + 'not_found' => "O processador AJAX ':name' não foi encontrado.", ], 'account' => [ + 'impersonate' => 'Personificar utilizador', + 'impersonate_confirm' => 'Tem a certeza de que quer personificar este utilizador? Pode voltar ao seu estado inicial fazendo log out.', + 'impersonate_success' => 'Está agora a personificar este utilizador', + 'impersonate_working' => 'A personificar...', + 'impersonating' => 'A personificar :full_name', + 'stop_impersonating' => 'Parar de personificar', + 'signed_in_as' => 'Sessão iniciada como :full_name', 'sign_out' => 'Sair', 'login' => 'Entrar', 'reset' => 'Redefinir', 'restore' => 'Restaurar', 'login_placeholder' => 'Utilizador', 'password_placeholder' => 'Senha', + 'remember_me' => 'Manter sessão activa', 'forgot_password' => 'Esqueceu sua senha?', 'enter_email' => 'Coloque o seu email', 'enter_login' => 'Coloque o nome de utilizador', @@ -55,26 +75,26 @@ 'dashboard' => [ 'menu_label' => 'Painel', 'widget_label' => 'Widget', - 'widget_width' => 'Width', - 'full_width' => 'full width', - 'manage_widgets' => 'Manage widgets', - 'add_widget' => 'Add widget', - 'widget_inspector_title' => 'Widget configuration', - 'widget_inspector_description' => 'Configure the report widget', - 'widget_columns_label' => 'Width :columns', - 'widget_columns_description' => 'The widget width, a number between 1 and 10.', - 'widget_columns_error' => 'Please enter the widget width as a number between 1 and 10.', - 'columns' => '{1} column|[2,Inf] columns', - 'widget_new_row_label' => 'Force new row', - 'widget_new_row_description' => 'Put the widget in a new row.', - 'widget_title_label' => 'Widget title', - 'widget_title_error' => 'The Widget Title is required.', - 'reset_layout' => 'Reset layout', - 'reset_layout_confirm' => 'Reset layout back to default?', - 'reset_layout_success' => 'Layout has been reset', - 'make_default' => 'Make default', - 'make_default_confirm' => 'Set the current layout as the default?', - 'make_default_success' => 'Current layout is now the default', + 'widget_width' => 'Largura', + 'full_width' => 'Largura completa', + 'manage_widgets' => 'Gerir widgets', + 'add_widget' => 'Adicionar widget', + 'widget_inspector_title' => 'Configuração de widgets', + 'widget_inspector_description' => 'Configurar o widget', + 'widget_columns_label' => 'Largura :columns', + 'widget_columns_description' => 'A largura do widget, um número entre 1 e 12.', + 'widget_columns_error' => 'Por favor introduza a largura do widget como um número entre 1 e 12.', + 'columns' => '{1} coluna|[2,Inf] colunas', + 'widget_new_row_label' => 'Forçar nova linha', + 'widget_new_row_description' => 'Pôr o widget numa linha nova.', + 'widget_title_label' => 'Título do widget', + 'widget_title_error' => 'O título do widget é obrigatório.', + 'reset_layout' => 'Reinicializar layout', + 'reset_layout_confirm' => 'Reinicializar o layout para a configuração de origem?', + 'reset_layout_success' => 'O layout foi reinicializado', + 'make_default' => 'Guardar como pré-definido', + 'make_default_confirm' => 'Guardar o layout actual como o pré-definido?', + 'make_default_success' => 'O layout actual é agora o pré-definido', 'collapse_all' => 'Contrair todos', 'expand_all' => 'Expandir todos ', 'status' => [ @@ -93,7 +113,7 @@ ], 'welcome' => [ 'widget_title_default' => 'Bem-vindo', - 'welcome_back_name' => 'Seja bem vindo no seu regresso ao :app, :name.', + 'welcome_back_name' => 'Seja bem vindo de volta ao :app, :name.', 'welcome_to_name' => 'Bem vindo ao :app, :name.', 'first_sign_in' => 'Esta é a primeira vez que acede à área administrativa.', 'last_sign_in' => 'O último acesso foi em', @@ -102,36 +122,40 @@ ] ], 'user' => [ - 'name' => 'Administrator', - 'menu_label' => 'Administrators', - 'menu_description' => 'Manage back-end administrator users, groups and permissions.', - 'list_title' => 'Manage Administrators', - 'new' => 'New Administrator', + 'name' => 'Administrador', + 'menu_label' => 'Administradores', + 'menu_description' => 'Gerir utilizadores, grupos, e permissões de administração.', + 'list_title' => 'Gerir Administradores', + 'new' => 'Novo Administrator', 'login' => 'Login', - 'first_name' => 'First Name', - 'last_name' => 'Last Name', - 'full_name' => 'Full Name', + 'first_name' => 'Nome Próprio', + 'last_name' => 'Apelido', + 'full_name' => 'Nome Completo', 'email' => 'Email', - 'groups' => 'Groups', - 'groups_comment' => 'Specify which groups the account should belong to. Groups define user permissions, which can be overriden on the user level, on the Permissions tab.', + 'role_field' => 'Papel', + 'role_comment' => 'Papéis definem permissões de utilizador, que podem ser sobrepostas para cada utilizador no separador Permissões.', + 'groups' => 'Grupos', + 'groups_comment' => 'Defina os grupos a que esta conta deve pertencer. Os grupos definem permissões, que podem ser sobrepostas para cada utilizador no separador Permissões.', 'avatar' => 'Avatar', - 'password' => 'Password', - 'password_confirmation' => 'Confirm Password', - 'permissions' => 'Permissions', - 'account' => 'Account', - 'superuser' => 'Super User', - 'superuser_comment' => 'Grants this account unlimited access to all areas of the system. Super users can add and manage other users. ', - 'send_invite' => 'Send invitation by email', - 'send_invite_comment' => 'Sends a welcome message containing login and password information.', - 'delete_confirm' => 'Delete this administrator?', - 'return' => 'Return to admin list', - 'allow' => 'Allow', - 'inherit' => 'Inherit', - 'deny' => 'Deny', + 'password' => 'Senha', + 'password_confirmation' => 'Confirmar Senha', + 'permissions' => 'Permissões', + 'account' => 'Conta', + 'superuser' => 'Super Utilizador', + 'superuser_comment' => 'Permite accesso completo a todas as àreas do sistema para esta conta. Super utilizadores podem criar e gerir outros utilizadores.', + 'send_invite' => 'Enviar convite por email', + 'send_invite_comment' => 'Envia uma mensagem de boas-vindas com a informação de login e password.', + 'delete_confirm' => 'Apagar este administrador?', + 'return' => 'Voltar à lista de administradores', + 'allow' => 'Permitir', + 'inherit' => 'Herdar', + 'deny' => 'Negar', 'activated' => 'Activado', 'last_login' => 'Última entrada', 'created_at' => 'Criado em', 'updated_at' => 'Modificado em', + 'deleted_at' => 'Apagado em', + 'show_deleted' => 'Mostrar apagados', 'group' => [ 'name' => 'Grupo', 'name_comment' => 'O nome é exibido na lista de grupos ao criar/alterar um administrador.', @@ -146,11 +170,27 @@ 'new' => 'Novo grupo administrador', 'delete_confirm' => 'Você realmente deseja apagar este grupo?', 'return' => 'Voltar para a lista de grupos', - 'users_count' => 'Utilizadores' + 'users_count' => 'Utilizadores', + ], + 'role' => [ + 'name' => 'Papel', + 'name_field' => 'Nome', + 'name_comment' => 'O nome é exibido na lista de grupos ao criar/alterar um administrador.', + 'description_field' => 'Descrição', + 'code_field' => 'Código', + 'code_comment' => 'Insira um código exclusivo se quiser utilizar o mesmo com a API.', + 'menu_label' => 'Gerir Papéis', + 'list_title' => 'Gerir Papéis', + 'new' => 'Novo Papel', + 'delete_confirm' => 'Você realmente deseja apagar este papel?', + 'return' => 'Voltar para a lista de papéis', + 'users_count' => 'Utilizadores', ], 'preferences' => [ 'not_authenticated' => 'Nenhum utilizador autenticado para carregar as preferências.', ], + 'trashed_hint_title' => 'Esta conta foi apagada', + 'trashed_hint_desc' => 'Esta conta foi apagada e não pode iniciar sessão. Para a restaurar, clique no botão Restaurar Utilizador no canto inferior direito.', ], 'list' => [ 'default_title' => 'Lista', @@ -181,7 +221,7 @@ 'delete_selected_confirm' => 'Apagar os registos selecionados?', 'delete_selected_success' => 'Registos seleccionados apagados com sucesso.', 'column_switch_true' => 'Sim', - 'column_switch_false' => 'Não' + 'column_switch_false' => 'Não', ], 'fileupload' => [ 'attachment' => 'Anexo', @@ -193,7 +233,11 @@ 'upload_file' => 'Enviar ficheiro', 'upload_error' => 'Erro ao enviar', 'remove_confirm' => 'Tem a certeza?', - 'remove_file' => 'Remover ficheiro' + 'remove_file' => 'Remover ficheiro', + ], + 'repeater' => [ + 'min_items_failed' => ':name requer no mínimo :min itens, apenas :items foram introduzidos', + 'max_items_failed' => ':name requer no máximo :min itens, :items foram introduzidos', ], 'form' => [ 'create_title' => 'Novo :name', @@ -202,6 +246,7 @@ 'create_success' => ':name foi criado com sucesso', 'update_success' => ':name foi actualizado com sucesso', 'delete_success' => ':name foi apagado com sucesso', + 'restore_success' => ':name foi restaurado com sucesso', 'reset_success' => 'Reinicialização completa', 'missing_id' => 'O ID do registo não foi fornecido', 'missing_model' => 'Formulário utilizado na classe :class não tem um modelo definido.', @@ -221,6 +266,9 @@ 'confirm_delete' => 'Realmente deseja apagar este registo?', 'confirm_delete_multiple' => 'Realmente deseja apagar os registos seleccionados?', 'deleting_name' => 'Apagando :name...', + 'restore' => 'Restaurar', + 'restoring' => 'Restaurando', + 'confirm_restore' => 'Realmente deseja restaurar este registo?', 'reset_default' => 'Redefinir para o padrão', 'resetting' => 'Redefinindo', 'resetting_name' => 'Redefinindo :name', @@ -254,11 +302,12 @@ ], 'recordfinder' => [ 'find_record' => 'Localizar Registo', + 'invalid_model_class' => 'A classe modelo ":modelClass" definida para o localizador de registos é inválida.', 'cancel' => 'Cancelar', ], 'pagelist' => [ 'page_link' => 'Ligação de página', - 'select_page' => 'Escolha uma página...' + 'select_page' => 'Escolha uma página...', ], 'relation' => [ 'missing_config' => 'Comportamento da relação não tem uma configuração para ":config".', @@ -312,6 +361,8 @@ 'permissions' => 'Diretoria :name ou suas subdiretorias não são graváveis pelo PHP. Por favor, defina permissões de escrita para o servidor nesta diretoria.', 'extension' => 'A extensão PHP :name não está instalada. Por favor, instale esta biblioteca para activar a extensão.', 'plugin_missing' => 'A extensão :name é uma dependência mas não está instalada. Por favor instale esta extensão.', + 'debug' => 'O modo de depuração está activo. Isto não é recomendado em abientes de produção.', + 'decompileBackendAssets' => 'Os recursos do backend não estao compilados. Isto não é recomendado em ambientes de produção.', ], 'editor' => [ 'menu_label' => 'Definições do Editor', @@ -358,9 +409,13 @@ 'no_wrap_comment' => 'Lista de etiquetas que não devem ser envolvidas num bloco de etiquetas.', 'remove_tags' => 'Apagar etiquetas', 'remove_tags_comment' => 'Lista de etiquetas que serão excluídas incluíndo o conteúdo.', + 'line_breaker_tags' => 'Etiquetas de quebra de linha', + 'line_breaker_tags_comment' => 'Lista de etiquetas entre as quais é inserida uma quebra de linha.', + 'toolbar_buttons' => 'Botões da barra de ferramentas', + 'toolbar_buttons_comment' => 'Botões da barra de ferramentas do editor rico a serem mostradas por defeito. [fullscreen, bold, italic, underline, strikeThrough, subscript, superscript, fontFamily, fontSize, |, color, emoticons, inlineStyle, paragraphStyle, |, paragraphFormat, align, formatOL, formatUL, outdent, indent, quote, insertHR, -, insertLink, insertImage, insertVideo, insertAudio, insertFile, insertTable, undo, redo, clearFormatting, selectAll, html]', ], 'tooltips' => [ - 'preview_website' => 'Prévisualizar a página' + 'preview_website' => 'Prévisualizar a página', ], 'mysettings' => [ 'menu_label' => 'As minhas configurações', @@ -369,7 +424,7 @@ 'myaccount' => [ 'menu_label' => 'Minha Conta', 'menu_description' => 'Actualizar detalhes da sua conta, como nome, e-mail e senha.', - 'menu_keywords' => 'login de segurança' + 'menu_keywords' => 'login de segurança', ], 'branding' => [ 'menu_label' => 'Personalização', @@ -377,6 +432,8 @@ 'brand' => 'Marca', 'logo' => 'Logo', 'logo_description' => 'Fazer carregamento de um logótipo para usar na área administrativa.', + 'favicon' => 'Favicon', + 'favicon_description' => 'Carrege um favicon personalizado a usar na área administrativa', 'app_name' => 'Nome da Aplicação', 'app_name_description' => 'Este nome é mostrado no título da área administrativa.', 'app_tagline' => 'Slogan do Aplicativo', @@ -390,8 +447,9 @@ 'navigation' => 'Navegação', 'menu_mode' => 'Estilo de menu', 'menu_mode_inline' => 'Em linha', + 'menu_mode_inline_no_icons' => 'Em linha (sem icons)', 'menu_mode_tile' => 'Blocos', - 'menu_mode_collapsed' => 'Colapsados' + 'menu_mode_collapsed' => 'Colapsados', ], 'backend_preferences' => [ 'menu_label' => 'Preferências da Administração', @@ -407,21 +465,25 @@ 'hint' => 'Este registo mostra a lista de acessos dos administradores. Os registros são mantidos por um período de :days dias.', 'menu_label' => 'Registo de Acesso', 'menu_description' => 'Veja a lista de acessos à administração.', + 'id' => 'ID', 'created_at' => 'Data & Hora', + 'type' => 'Tipo', 'login' => 'Entrada', 'ip_address' => 'Endereço IP', 'first_name' => 'Nome', - 'last_name' => 'Sobrenome', + 'last_name' => 'Apelido', 'email' => 'E-mail', ], 'filter' => [ 'all' => 'todos', 'options_method_not_exists' => "A classe modelo :model deve definir um método :method() retornando opções para o filtro ':filter'.", - 'date_all' => 'todo o período' + 'date_all' => 'todo o período', + 'number_all' => 'todos os números', ], 'import_export' => [ 'upload_csv_file' => '1. Enviar ficheiro CSV', 'import_file' => 'Importar ficheiro', + 'row' => 'Linha :row', 'first_row_contains_titles' => 'Primeira linha contém títulos das colunas', 'first_row_contains_titles_desc' => 'Deixe marcado se primeira linha do CSV é utilizada como títulos das colunas.', 'match_columns' => '2. Associar as colunas do ficheiro a campos do base de dados', @@ -488,15 +550,16 @@ 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Celtic)', 'iso_8859_15' => 'ISO-8859-15 (Latin-9, Western European revision with euro sign)', 'windows_1251' => 'Windows-1251 (CP1251)', - 'windows_1252' => 'Windows-1252 (CP1252)' - ] + 'windows_1252' => 'Windows-1252 (CP1252)', + ], ], 'permissions' => [ - 'manage_media' => 'Gerir conteúdo multimédia' + 'manage_media' => 'Gerir conteúdo multimédia', ], 'mediafinder' => [ 'label' => 'Localizador de multimédia', - 'default_prompt' => 'Clique no botão %s para localizar um ficheiro multimédia' + 'default_prompt' => 'Clique no botão %s para localizar um ficheiro multimédia', + 'no_image' => 'A imagem não foi encontrada', ], 'media' => [ 'menu_label' => 'Conteúdos', @@ -527,6 +590,9 @@ 'uploading_error' => 'Falha no envio', 'type_blocked' => 'O tipo de ficheiro utilizado é bloqueado por motivos de segurança.', 'order_by' => 'Ordenar por', + 'direction' => 'Direção', + 'direction_asc' => 'Ascendente', + 'direction_desc' => 'Descendente', 'folder' => 'Pasta', 'no_files_found' => 'Nenhum ficheiro encontrado.', 'delete_empty' => 'Por favor, selecione itens para apagar.', @@ -556,6 +622,6 @@ 'selection_mode' => 'Modo de seleção', 'resize_image' => 'Redimensionar imagem', 'image_size' => 'Tamanho da imagem:', - 'selected_size' => 'Selecionado:' + 'selected_size' => 'Selecionado:', ], ]; From 9ed6bdefdc0c18ead72eb935c8d50da696ba27e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szab=C3=B3=20Gerg=C5=91?= Date: Fri, 11 Oct 2019 17:48:21 +0200 Subject: [PATCH 070/157] Improved Hungarian translation (#4682) Credit to @gergo85 --- modules/backend/lang/hu/lang.php | 34 ++++++++++++++++++++------------ modules/system/lang/hu/lang.php | 12 ++++++++++- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/modules/backend/lang/hu/lang.php b/modules/backend/lang/hu/lang.php index 95380149b5..9c326b99b0 100644 --- a/modules/backend/lang/hu/lang.php +++ b/modules/backend/lang/hu/lang.php @@ -24,7 +24,7 @@ ], 'access_denied' => [ 'label' => 'Hozzáférés megtagadva', - 'help' => 'Ön nem rendelkezik a szükséges engedélyekkel ennek a lapnak a megtekintéséhez.', + 'help' => 'Nem rendelkezik a szükséges engedélyekkel ennek a lapnak a megtekintéséhez.', 'cms_link' => 'Vissza a látogatói oldalra' ], 'no_database' => [ @@ -42,6 +42,12 @@ 'not_found' => "A(z) ':name' AJAX handler nem található." ], 'account' => [ + 'impersonate' => 'Átjelentkezés a fiókba', + 'impersonate_confirm' => 'Biztos benne, hogy átjelentkezik a felhasználó saját fiókjába? Ezáltal a jelenlegi munkamenetből ki lesz jelentkeztetve.', + 'impersonate_success' => 'Sikeresen átjelentkezett a másik fiókba', + 'impersonate_working' => 'Átjelentkezés...', + 'impersonating' => 'Átjelentkezve mint :full_name', + 'stop_impersonating' => 'Visszajelentkezés', 'signed_in_as' => 'Belépve mint :full_name', 'sign_out' => 'Kijelentkezés', 'login' => 'Belépés', @@ -134,12 +140,12 @@ 'password' => 'Jelszó', 'password_confirmation' => 'Jelszó megerősítése', 'permissions' => 'Engedélyek', - 'account' => 'Fiók', + 'account' => 'Profil', 'superuser' => 'Szuperadmin', 'superuser_comment' => 'Korlátlan hozzáférést biztosít az admin felülethez.', 'send_invite' => 'Meghívó küldése e-mailben', 'send_invite_comment' => 'Csak a belépéshez szükséges adatokat tartalmazza.', - 'delete_confirm' => 'Valóban törölni akarja az admint?', + 'delete_confirm' => 'Valóban törölni akarja ezt a felhasználót?', 'return' => 'Vissza az adminokhoz', 'allow' => 'Engedélyezés', 'inherit' => 'Öröklés', @@ -280,18 +286,18 @@ 'or' => 'vagy', 'confirm_tab_close' => 'Valóban be akarja zárni a fület? El fognak veszni a nem mentett módosítások.', 'behavior_not_ready' => 'Nem történt meg az űrlap viselkedésének inicializálása. Kérjük ellenőrizze, hogy meghívta-e az initForm() függvényt a vezérlőben.', - 'preview_no_files_message' => 'Nincsenek feltöltve fájlok.', - 'preview_no_media_message' => 'Nincs kiválasztva média.', - 'preview_no_record_message' => 'Nincs kiválasztva mező.', + 'preview_no_files_message' => 'Nincs megadva fájl.', + 'preview_no_media_message' => 'Nincs megadva kép.', + 'preview_no_record_message' => 'Nincs megadva mező.', 'select' => 'Kiválaszt', - 'select_all' => 'mindet kiválaszt', - 'select_none' => 'ne válasszon egyet', + 'select_all' => 'mindegyik', + 'select_none' => 'egyik sem', 'select_placeholder' => 'válasszon', 'insert_row' => 'Sor beszúrása', 'insert_row_below' => 'Sor beszúrása alá', 'delete_row' => 'Sor törlése', 'concurrency_file_changed_title' => 'A fájl megváltozott', - 'concurrency_file_changed_description' => 'Az Ön által szerkesztett fájlt már egy másik felhasználó módosította. Újratöltheti a fájlt és elveszti a változtatásait, vagy felülírja a fájlt.', + 'concurrency_file_changed_description' => 'A jelenleg szerkesztett fájlt egy másik felhasználó már módosította. Újratöltheti és elveszti a változtatásait, vagy felülírja a fájlt.', 'return_to_list' => 'Vissza a listához' ], 'recordfinder' => [ @@ -350,11 +356,13 @@ 'mass_assignment_failed' => "A tömeges hozzárendelés a(z) ':attribute' modell attribútumhoz nem sikerült." ], 'warnings' => [ - 'tips' => 'Rendszer beállítási tippek', - 'tips_description' => 'Olyan problémák vannak, melyekre figyeljen oda a rendszer megfelelő működése érdekében.', + 'tips' => 'Beállítási tippek', + 'tips_description' => 'Az alábbi dolgokra figyeljen oda a rendszer megfelelő működése érdekében.', 'permissions' => 'A(z) :name könyvtár vagy alkönyvtárai a PHP számára nem írhatóak. Adjon megfelelő engedélyeket a kiszolgálónak erre a könyvtárra.', 'extension' => 'A(z) :name PHP kiterjesztés nincs telepítve. Telepítse ezt a függvénytárat és aktiválja a kiterjesztést.', - 'plugin_missing' => 'A(z) :name bővítményre szükség van, de nincs telepítve. Kérjük telepítse ezt a bővítményt.' + 'plugin_missing' => 'A(z) :name bővítményre szükség van, de nincs telepítve. Kérjük telepítse ezt a bővítményt.', + 'debug' => 'A hibakeresési mód engedélyezve van. Ez nem ajánlott éles weboldal esetén.', + 'decompileBackendAssets' => 'Az admin felülethez tartozó fájlok nem véglegesek. Ez nem ajánlott éles weboldal esetén.' ], 'editor' => [ 'menu_label' => 'Szövegszerkesztő', @@ -615,5 +623,5 @@ 'resize_image' => 'Kép átméretezése', 'image_size' => 'Kép mérete:', 'selected_size' => 'Kiválasztva:' - ], + ] ]; diff --git a/modules/system/lang/hu/lang.php b/modules/system/lang/hu/lang.php index c6543ba7c3..9b3e99652a 100644 --- a/modules/system/lang/hu/lang.php +++ b/modules/system/lang/hu/lang.php @@ -155,6 +155,9 @@ 'ses_key_comment' => 'Adja meg az API kulcsot', 'ses_secret' => 'SES kód', 'ses_secret_comment' => 'Adja meg az API titkos kulcsot', + 'sparkpost' => 'SparkPost', + 'sparkpost_secret' => 'SparkPost kód', + 'sparkpost_secret_comment' => 'Adja meg az API titkos kulcsot', 'ses_region' => 'SES régió', 'ses_region_comment' => 'Adja meg a régiót (pl. us-east-1)', 'drivers_hint_header' => 'Hiányzó komponens', @@ -388,6 +391,7 @@ 'manage_mail_templates' => 'Levél sablonok kezelése', 'manage_mail_settings' => 'Levelezési beállítások kezelése', 'manage_other_administrators' => 'Adminisztrátorok kezelése', + 'impersonate_users' => 'Átjelentkezés felhasználók fiókjába', 'manage_preferences' => 'Saját beállítások kezelése', 'manage_editor' => 'Kódszerkesztő testreszabása', 'view_the_dashboard' => 'Vezérlőpult elérése', @@ -415,8 +419,14 @@ 'help' => 'Sajnáljuk, de hiba történt, ezért az oldal nem megjeleníthető.' ], 'invalid_token' => [ - 'label' => 'A biztonsági kód érvényessége lejárt. Kérjük töltse be újra az oldalt.', + 'label' => 'Biztonsági kód érvényessége lejárt. Kérjük töltse be újra az oldalt.' ], + 'maintenance' => [ + 'label' => 'Hamarosan visszatérünk!', + 'help' => 'A weboldal karbantartás alatt áll. Látogasson vissza később!', + 'message' => 'Üzenet:', + 'available_at' => 'Újrapróbálás:' + ] ], 'pagination' => [ 'previous' => 'Előző', From ffcdcdb1e29c4daa6309b60a2d7869c17953b3d9 Mon Sep 17 00:00:00 2001 From: Piotr Karecki Date: Fri, 11 Oct 2019 20:12:08 +0200 Subject: [PATCH 071/157] Move prompt to lang Move default prompt text to i18n file. --- modules/backend/formwidgets/Repeater.php | 4 +++- modules/backend/lang/en/lang.php | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/backend/formwidgets/Repeater.php b/modules/backend/formwidgets/Repeater.php index 724bb2c526..e25df461fa 100644 --- a/modules/backend/formwidgets/Repeater.php +++ b/modules/backend/formwidgets/Repeater.php @@ -21,7 +21,7 @@ class Repeater extends FormWidgetBase /** * @var string Prompt text for adding new items. */ - public $prompt = 'Add new item'; + public $prompt; /** * @var bool Items can be sorted. @@ -97,6 +97,8 @@ class Repeater extends FormWidgetBase */ public function init() { + $this->prompt = Lang::get('backend::lang.repeater.add_new_item'); + $this->fillFromConfig([ 'form', 'prompt', diff --git a/modules/backend/lang/en/lang.php b/modules/backend/lang/en/lang.php index f550839d6d..5aacad895b 100644 --- a/modules/backend/lang/en/lang.php +++ b/modules/backend/lang/en/lang.php @@ -236,6 +236,7 @@ 'remove_file' => 'Remove file' ], 'repeater' => [ + 'add_new_item' => 'Add new item', 'min_items_failed' => ':name requires a minimum of :min items, only :items were provided', 'max_items_failed' => ':name only allows up to :max items, :items were provided', ], From 7d948fc5db1fe01aab45c656322952ef062640ba Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Sun, 13 Oct 2019 06:15:19 -0600 Subject: [PATCH 072/157] Trigger change event on clearing recordfinder Fixes #3591. --- .../backend/formwidgets/recordfinder/partials/_recordfinder.htm | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/backend/formwidgets/recordfinder/partials/_recordfinder.htm b/modules/backend/formwidgets/recordfinder/partials/_recordfinder.htm index 8ebb2dd705..65878029e8 100644 --- a/modules/backend/formwidgets/recordfinder/partials/_recordfinder.htm +++ b/modules/backend/formwidgets/recordfinder/partials/_recordfinder.htm @@ -28,6 +28,7 @@ class="btn btn-default clear-record" data-request="getEventHandler('onClearRecord') ?>" data-request-confirm="" + data-request-success="$('#getId() ?>').trigger('change')" aria-label="Remove"> From 5499c24cf9030516bf86f5cdf4f429ca5efd4264 Mon Sep 17 00:00:00 2001 From: Valentijn Evers <32770383+vevers@users.noreply.github.com> Date: Mon, 14 Oct 2019 09:33:43 +0200 Subject: [PATCH 073/157] Improved email client support for branded mails (#4663) Improves compatibility with Outlook mail clients, preventing harsh word breaks. Credit to @vevers. --- modules/system/models/mailbrandsetting/custom.less | 8 ++++++-- modules/system/views/mail/partial-panel.htm | 2 +- modules/system/views/mail/partial-promotion.htm | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/modules/system/models/mailbrandsetting/custom.less b/modules/system/models/mailbrandsetting/custom.less index 430f50bbcf..f75a5b6cd6 100644 --- a/modules/system/models/mailbrandsetting/custom.less +++ b/modules/system/models/mailbrandsetting/custom.less @@ -13,11 +13,10 @@ body { line-height: 1.4; margin: 0; -moz-hyphens: auto; - -ms-word-break: break-all; + -ms-word-break: break-word; width: 100% !important; -webkit-hyphens: auto; -webkit-text-size-adjust: none; - word-break: break-all; word-break: break-word; } @@ -75,6 +74,7 @@ code { color: @text-color; font-size: 16px; line-height: 1.5em; + word-break: break-all; } p.sub { @@ -85,6 +85,10 @@ img { max-width: 100%; } +.break-all, .break-all * { + word-break: break-all; +} + /* Layout */ .wrapper { diff --git a/modules/system/views/mail/partial-panel.htm b/modules/system/views/mail/partial-panel.htm index fa6ef4a9f6..5fdb48eb0a 100644 --- a/modules/system/views/mail/partial-panel.htm +++ b/modules/system/views/mail/partial-panel.htm @@ -2,7 +2,7 @@ == {{ body|trim }} == - +
- +
diff --git a/modules/system/views/mail/partial-promotion.htm b/modules/system/views/mail/partial-promotion.htm index fe9e877fc1..90854f3a6f 100644 --- a/modules/system/views/mail/partial-promotion.htm +++ b/modules/system/views/mail/partial-promotion.htm @@ -2,7 +2,7 @@ == {{ body|trim }} == -
+
+ - + mode === 'radio') : ?> - + @@ -24,13 +26,19 @@ code, $permissionsData) - ? $permissionsData[$permission->code] - : 0; - } - else { - $isChecked = array_key_exists($permission->code, $permissionsData); + switch ($this->mode) { + case 'radio': + $permissionValue = array_key_exists($permission->code, $permissionsData) + ? $permissionsData[$permission->code] + : 0; + break; + case 'switch': + $isChecked = !((int) @$permissionsData[$permission->code] === -1); + break; + case 'checkbox': + default: + $isChecked = array_key_exists($permission->code, $permissionsData); + break; } $allowId = $this->getId('permission-' . $globalIndex . '-allow'); @@ -42,13 +50,14 @@ "> + - - - + - + mode === 'switch'): ?> + + + + From d936cc360cdf93fabe89ae71826ca7aed564aa0d Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Tue, 15 Oct 2019 17:37:59 -0600 Subject: [PATCH 075/157] Added ability to filter down the permissions presented by the PermissionEditor You can now specify an array of "availablePermissions" to the PermissionEditor FormWidget that it will use to further down the list of permissions that are up for managment by the current user. --- .../backend/formwidgets/PermissionEditor.php | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/modules/backend/formwidgets/PermissionEditor.php b/modules/backend/formwidgets/PermissionEditor.php index 72842a8113..be7c81acbb 100644 --- a/modules/backend/formwidgets/PermissionEditor.php +++ b/modules/backend/formwidgets/PermissionEditor.php @@ -23,6 +23,10 @@ * 1: Explicitly allow the permission * -1: Explicitly deny the permission * + * Available permissions can be defined in the form of an array of permission codes to allow: + * NOTE: Users are still not allowed to modify permissions that they themselves do not have access to + * availablePermissions: ['some.author.permission', 'some.other.permission', 'etc.some.system.permission'] + * * @package october\backend * @author Alexey Bobkov, Samuel Georges */ @@ -35,13 +39,19 @@ class PermissionEditor extends FormWidgetBase */ public $mode = 'radio'; + /** + * @var array Permission codes to allow to be interacted with through this widget + */ + public $availablePermissions; + /** * @inheritDoc */ public function init() { $this->fillFromConfig([ - 'mode' + 'mode', + 'availablePermissions', ]); $this->user = BackendAuth::getUser(); @@ -137,13 +147,13 @@ protected function getFilteredPermissions() { $permissions = BackendAuth::listTabbedPermissions(); - if ($this->user->isSuperUser()) { - return $permissions; - } - foreach ($permissions as $tab => $permissionsArray) { foreach ($permissionsArray as $index => $permission) { - if (!$this->user->hasAccess($permission->code)) { + if (!$this->user->hasAccess($permission->code) || + ( + is_array($this->availablePermissions) && + !in_array($permission->code, $this->availablePermissions) + )) { unset($permissionsArray[$index]); } } From 3bcf9e318b4d7a9385ca3d625f80281485795564 Mon Sep 17 00:00:00 2001 From: Ben Thomson Date: Mon, 21 Oct 2019 05:47:37 +0800 Subject: [PATCH 076/157] Add clear classes for fields (#4706) Credit to @bennothommo. Added `clear-full`, `clear-left`, and `clear-right` CSS classes that can be used to apply clearfixes to form fields by adding them to the field's `cssClass` property --- modules/system/assets/ui/less/form.less | 12 ++++++++++++ modules/system/assets/ui/storm.css | 3 +++ 2 files changed, 15 insertions(+) diff --git a/modules/system/assets/ui/less/form.less b/modules/system/assets/ui/less/form.less index dd83ab1d12..075b2fc0a0 100644 --- a/modules/system/assets/ui/less/form.less +++ b/modules/system/assets/ui/less/form.less @@ -155,6 +155,18 @@ clear: right; } + &.clear-full { + clear: both; + } + + &.clear-left { + clear: left; + } + + &.clear-right { + clear: right; + } + &.layout-relative { padding-bottom: 0; } diff --git a/modules/system/assets/ui/storm.css b/modules/system/assets/ui/storm.css index e6d363a72b..e37b2c0535 100644 --- a/modules/system/assets/ui/storm.css +++ b/modules/system/assets/ui/storm.css @@ -4200,6 +4200,9 @@ html.cssanimations .cursor-loading-indicator.hide {display:none} .form-group.span-full {width:100%;float:left} .form-group.span-left {float:left;width:48.5%;clear:left} .form-group.span-right {float:right;width:48.5%;clear:right} +.form-group.clear-full {clear:both} +.form-group.clear-left {clear:left} +.form-group.clear-right {clear:right} .form-group.layout-relative {padding-bottom:0} .form-group.checkbox-field {padding-bottom:5px} .form-group.number-field >.form-control {text-align:right} From 1c7c438a09916baaaac396de557b2c212a812fb7 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Thu, 24 Oct 2019 20:19:20 +1100 Subject: [PATCH 077/157] Implement XSRF checking for AJAX handlers Refs #4699 Refs #4701 --- modules/cms/classes/Controller.php | 55 ++++++++++++++++--- modules/system/assets/js/framework-min.js | 8 +++ .../assets/js/framework.combined-min.js | 8 +++ modules/system/assets/js/framework.js | 20 +++++++ 4 files changed, 83 insertions(+), 8 deletions(-) diff --git a/modules/cms/classes/Controller.php b/modules/cms/classes/Controller.php index 239c46a33a..a07354a375 100644 --- a/modules/cms/classes/Controller.php +++ b/modules/cms/classes/Controller.php @@ -6,12 +6,14 @@ use View; use Lang; use Flash; +use Crypt; use Config; use Session; use Request; use Response; use Exception; use BackendAuth; +use Carbon\Carbon; use Twig\Environment as TwigEnvironment; use Twig\Cache\FilesystemCache as TwigCacheFilesystem; use Cms\Twig\Loader as TwigLoader; @@ -25,6 +27,7 @@ use October\Rain\Exception\AjaxException; use October\Rain\Exception\ValidationException; use October\Rain\Parse\Bracket as TextParser; +use Symfony\Component\HttpFoundation\Cookie; use Illuminate\Http\RedirectResponse; /** @@ -147,6 +150,13 @@ public function run($url = '/') $url = '/'; } + /* + * Check security token. + */ + if (!$this->verifyCsrfToken()) { + return Response::make(Lang::get('system::lang.page.invalid_token.label'), 403); + } + /* * Hidden page */ @@ -256,7 +266,13 @@ public function run($url = '/') return $result; } - return Response::make($result, $this->statusCode); + $response = Response::make($result, $this->statusCode); + + if (Config::get('cms.enableCsrfProtection')) { + $this->addCsrfCookie($response); + } + + return $response; } /** @@ -802,13 +818,6 @@ protected function execAjaxHandlers() */ protected function runAjaxHandler($handler) { - /* - * Check security token. - */ - if (!$this->verifyCsrfToken()) { - return Response::make(Lang::get('system::lang.page.invalid_token.label'), 403); - } - /** * @event cms.ajax.beforeRunHandler * Provides an opportunity to modify an AJAX request @@ -1583,6 +1592,32 @@ protected function setComponentPropertiesFromParams($component, $parameters = [] // Security // + /** + * Adds anti-CSRF cookie. + * Adds a cookie with a token for CSRF checks to the response. + * @return void + */ + protected function addCsrfCookie(\Illuminate\Http\Response $response) + { + $config = Config::get('session'); + + $response->headers->setCookie( + new Cookie( + 'XSRF-TOKEN', + Session::token(), + Carbon::now()->addSeconds(60 * $config['lifetime'])->getTimestamp(), + $config['path'], + $config['domain'], + $config['secure'], + false, + false, + $config['same_site'] ?? null + ) + ); + + return $response; + } + /** * Checks the request data / headers for a valid CSRF token. * Returns false if a valid token is not found. Override this @@ -1601,6 +1636,10 @@ protected function verifyCsrfToken() $token = Request::input('_token') ?: Request::header('X-CSRF-TOKEN'); + if (!$token && $header = Request::header('X-XSRF-TOKEN')) { + $token = Crypt::decrypt($header); + } + if (!strlen($token) || !strlen(Session::token())) { return false; } diff --git a/modules/system/assets/js/framework-min.js b/modules/system/assets/js/framework-min.js index 43fe38ba46..eb8f52fbc8 100644 --- a/modules/system/assets/js/framework-min.js +++ b/modules/system/assets/js/framework-min.js @@ -14,6 +14,8 @@ useFiles=false} if($.type(loading)=='string'){loading=$(loading)} var requestHeaders={'X-OCTOBER-REQUEST-HANDLER':handler,'X-OCTOBER-REQUEST-PARTIALS':this.extractPartials(options.update)} if(useFlash){requestHeaders['X-OCTOBER-REQUEST-FLASH']=1} +var csrfToken=getCSRFToken() +if(csrfToken){requestHeaders['X-XSRF-TOKEN']=csrfToken} var requestData,inputName,data={} $.each($el.parents('[data-request-data]').toArray().reverse(),function extendRequest(){$.extend(data,paramToObj('data-request-data',$(this).data('request-data')))}) if($el.is(':input')&&!$form.length){inputName=$el.attr('name') @@ -112,6 +114,12 @@ function paramToObj(name,value){if(value===undefined)value='' if(typeof value=='object')return value try{return ocJSON("{"+value+"}")} catch(e){throw new Error('Error parsing the '+name+' attribute value. '+e)}} +function getCSRFToken(){var cookieValue=null +if(document.cookie&&document.cookie!=''){var cookies=document.cookie.split(';') +for(var i=0;i Date: Mon, 28 Oct 2019 12:58:07 -0600 Subject: [PATCH 078/157] Implement suggestions from @bennothommo --- modules/cms/classes/Controller.php | 8 ++++---- modules/system/assets/js/framework-min.js | 4 ++-- modules/system/assets/js/framework.combined-min.js | 4 ++-- modules/system/assets/js/framework.js | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/cms/classes/Controller.php b/modules/cms/classes/Controller.php index a07354a375..ae0198682d 100644 --- a/modules/cms/classes/Controller.php +++ b/modules/cms/classes/Controller.php @@ -269,7 +269,7 @@ public function run($url = '/') $response = Response::make($result, $this->statusCode); if (Config::get('cms.enableCsrfProtection')) { - $this->addCsrfCookie($response); + $this->addXsrfCookie($response); } return $response; @@ -1595,9 +1595,9 @@ protected function setComponentPropertiesFromParams($component, $parameters = [] /** * Adds anti-CSRF cookie. * Adds a cookie with a token for CSRF checks to the response. - * @return void + * @return Response */ - protected function addCsrfCookie(\Illuminate\Http\Response $response) + protected function addXsrfCookie(\Illuminate\Http\Response $response) { $config = Config::get('session'); @@ -1605,7 +1605,7 @@ protected function addCsrfCookie(\Illuminate\Http\Response $response) new Cookie( 'XSRF-TOKEN', Session::token(), - Carbon::now()->addSeconds(60 * $config['lifetime'])->getTimestamp(), + Carbon::now()->addMinutes((int) $config['lifetime'])->getTimestamp(), $config['path'], $config['domain'], $config['secure'], diff --git a/modules/system/assets/js/framework-min.js b/modules/system/assets/js/framework-min.js index eb8f52fbc8..acc69b4c4e 100644 --- a/modules/system/assets/js/framework-min.js +++ b/modules/system/assets/js/framework-min.js @@ -14,7 +14,7 @@ useFiles=false} if($.type(loading)=='string'){loading=$(loading)} var requestHeaders={'X-OCTOBER-REQUEST-HANDLER':handler,'X-OCTOBER-REQUEST-PARTIALS':this.extractPartials(options.update)} if(useFlash){requestHeaders['X-OCTOBER-REQUEST-FLASH']=1} -var csrfToken=getCSRFToken() +var csrfToken=getXSRFToken() if(csrfToken){requestHeaders['X-XSRF-TOKEN']=csrfToken} var requestData,inputName,data={} $.each($el.parents('[data-request-data]').toArray().reverse(),function extendRequest(){$.extend(data,paramToObj('data-request-data',$(this).data('request-data')))}) @@ -114,7 +114,7 @@ function paramToObj(name,value){if(value===undefined)value='' if(typeof value=='object')return value try{return ocJSON("{"+value+"}")} catch(e){throw new Error('Error parsing the '+name+' attribute value. '+e)}} -function getCSRFToken(){var cookieValue=null +function getXSRFToken(){var cookieValue=null if(document.cookie&&document.cookie!=''){var cookies=document.cookie.split(';') for(var i=0;i Date: Mon, 28 Oct 2019 13:33:07 -0600 Subject: [PATCH 079/157] Ensure that the XSRF cookie can always be added to the response, no matter the source of the response --- modules/cms/classes/Controller.php | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/modules/cms/classes/Controller.php b/modules/cms/classes/Controller.php index ae0198682d..5b09fa0387 100644 --- a/modules/cms/classes/Controller.php +++ b/modules/cms/classes/Controller.php @@ -136,11 +136,29 @@ public function __construct($theme = null) * Finds and serves the requested page. * If the page cannot be found, returns the page with the URL /404. * If the /404 page doesn't exist, returns the system 404 page. + * * If the parameter is omitted, the current URL used. + * * @param string $url Specifies the requested page URL. - * If the parameter is omitted, the current URL used. - * @return string Returns the processed page content. + * @return Response Returns the processed page content. */ public function run($url = '/') + { + $response = $this->runInternal($url); + + if (Config::get('cms.enableCsrfProtection') && $response instanceof \Symfony\Component\HttpFoundation\Response) { + $this->addXsrfCookie($response); + } + + return $response; + } + + /** + * Process the request internally + * + * @param string $url Specifies the requested page URL. + * @return Response Returns the processed page content. + */ + protected function runInternal($url = '/') { if ($url === null) { $url = Request::path(); @@ -266,13 +284,7 @@ public function run($url = '/') return $result; } - $response = Response::make($result, $this->statusCode); - - if (Config::get('cms.enableCsrfProtection')) { - $this->addXsrfCookie($response); - } - - return $response; + return Response::make($result, $this->statusCode); } /** From 6b127443ebf32c993788da973cabf486ffc6e6a3 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Tue, 29 Oct 2019 16:33:49 -0600 Subject: [PATCH 080/157] Fix typehint --- modules/cms/classes/Controller.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cms/classes/Controller.php b/modules/cms/classes/Controller.php index 5b09fa0387..44b2b5feab 100644 --- a/modules/cms/classes/Controller.php +++ b/modules/cms/classes/Controller.php @@ -1609,7 +1609,7 @@ protected function setComponentPropertiesFromParams($component, $parameters = [] * Adds a cookie with a token for CSRF checks to the response. * @return Response */ - protected function addXsrfCookie(\Illuminate\Http\Response $response) + protected function addXsrfCookie(\Symfony\Component\HttpFoundation\Response $response) { $config = Config::get('session'); From 9f80ebe8c87620596dbfbbb441704bf04dbdeb27 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Wed, 30 Oct 2019 08:08:54 -0600 Subject: [PATCH 081/157] Add cms.enableXsrfCookies config value (default true) to configure whether or not the XSRF cookie is automatically sent or if CSRF tokens are solely relied on. Related: https://github.com/octobercms/october/pull/4701#issuecomment-547773385 & https://github.com/laravel/framework/pull/24726 --- config/cms.php | 17 +++++++++++++++-- modules/cms/classes/Controller.php | 26 +++++++++++++++++--------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/config/cms.php b/config/cms.php index 86b58bcfeb..573b2822f6 100644 --- a/config/cms.php +++ b/config/cms.php @@ -374,13 +374,26 @@ | Cross Site Request Forgery (CSRF) Protection |-------------------------------------------------------------------------- | - | If the CSRF protection is enabled, all "postback" requests are checked - | for a valid security token. + | If the CSRF protection is enabled, all "postback" & AJAX requests are + | checked for a valid security token. | */ 'enableCsrfProtection' => true, + /* + |-------------------------------------------------------------------------- + | Automatic XSRF Cookies + |-------------------------------------------------------------------------- + | + | Automatically provide and process an XSRF cookie to the browser to + | support CSRF protection on all AJAX requests without having to add + | an explicit CSRF token to the frontend markup + | + */ + + 'enableXsrfCookies' => true, + /* |-------------------------------------------------------------------------- | Force bytecode invalidation diff --git a/modules/cms/classes/Controller.php b/modules/cms/classes/Controller.php index 44b2b5feab..ab7d57ad41 100644 --- a/modules/cms/classes/Controller.php +++ b/modules/cms/classes/Controller.php @@ -29,6 +29,7 @@ use October\Rain\Parse\Bracket as TextParser; use Symfony\Component\HttpFoundation\Cookie; use Illuminate\Http\RedirectResponse; +use Symfony\Component\HttpFoundation\Response as BaseResponse; /** * The CMS controller class. @@ -124,7 +125,7 @@ public function __construct($theme = null) throw new CmsException(Lang::get('cms::lang.theme.active.not_found')); } - $this->assetPath = Config::get('cms.themesPath', '/themes').'/'.$this->theme->getDirName(); + $this->assetPath = Config::get('cms.themesPath', '/themes') . '/' . $this->theme->getDirName(); $this->router = new Router($this->theme); $this->partialStack = new PartialStack; $this->initTwigEnvironment(); @@ -136,16 +137,21 @@ public function __construct($theme = null) * Finds and serves the requested page. * If the page cannot be found, returns the page with the URL /404. * If the /404 page doesn't exist, returns the system 404 page. - * * If the parameter is omitted, the current URL used. + * If the parameter is null, the current URL used. If it is not + * provided then '/' is used * - * @param string $url Specifies the requested page URL. - * @return Response Returns the processed page content. + * @param string|null $url Specifies the requested page URL. + * @return BaseResponse Returns the response to the provided URL */ public function run($url = '/') { $response = $this->runInternal($url); - if (Config::get('cms.enableCsrfProtection') && $response instanceof \Symfony\Component\HttpFoundation\Response) { + if ( + Config::get('cms.enableCsrfProtection', true) && + Config::get('cms.enableXsrfCookies', true) && + $response instanceof BaseResponse + ) { $this->addXsrfCookie($response); } @@ -156,7 +162,7 @@ public function run($url = '/') * Process the request internally * * @param string $url Specifies the requested page URL. - * @return Response Returns the processed page content. + * @return BaseResponse Returns the response to the provided URL */ protected function runInternal($url = '/') { @@ -1607,9 +1613,11 @@ protected function setComponentPropertiesFromParams($component, $parameters = [] /** * Adds anti-CSRF cookie. * Adds a cookie with a token for CSRF checks to the response. - * @return Response + * + * @param BaseResponse $response The response object to add the cookie to + * @return BaseResponse */ - protected function addXsrfCookie(\Symfony\Component\HttpFoundation\Response $response) + protected function addXsrfCookie(BaseResponse $response) { $config = Config::get('session'); @@ -1638,7 +1646,7 @@ protected function addXsrfCookie(\Symfony\Component\HttpFoundation\Response $res */ protected function verifyCsrfToken() { - if (!Config::get('cms.enableCsrfProtection')) { + if (!Config::get('cms.enableCsrfProtection', true)) { return true; } From d7ec6abdd9f412cddeb40ca98f8b0d9f093bdf48 Mon Sep 17 00:00:00 2001 From: Jan Boech Date: Wed, 30 Oct 2019 09:57:47 +0100 Subject: [PATCH 082/157] Typo in "Automatically run migrations on login" (#4727) Credit to @najbo. --- config/cms.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/cms.php b/config/cms.php index 573b2822f6..5c885e220d 100644 --- a/config/cms.php +++ b/config/cms.php @@ -98,7 +98,7 @@ | Automatically run migrations on login |-------------------------------------------------------------------------- | - | If value is true, UpdateMananger will be run on logging in to the backend. + | If value is true, UpdateManager will be run on logging in to the backend. | It's recommended to set this value to 'null' in production enviroments | because it clears the cache every time a user logs in to the backend. | If set to null, this setting is enabled when debug mode (app.debug) is enabled From 39dab2fa287c4b31a59b08cd0026f00a6096253b Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Sat, 2 Nov 2019 14:52:00 +1100 Subject: [PATCH 083/157] Cookies are no longer serialized Based on update to library https://github.com/octobercms/library/commit/09e859a13ee5663ee6cb6f0c02a4a97e09deefa7 we no longer serialize cookies, so the decrypter no longer needs to apply a serialization layer --- modules/backend/widgets/Lists.php | 2 ++ modules/cms/classes/Controller.php | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/backend/widgets/Lists.php b/modules/backend/widgets/Lists.php index 17d45631ff..c4bfd4f43f 100644 --- a/modules/backend/widgets/Lists.php +++ b/modules/backend/widgets/Lists.php @@ -1172,6 +1172,7 @@ protected function evalCustomListType($type, $record, $column, $value) /** * Process as text, escape the value + * @return string */ protected function evalTextTypeValue($record, $column, $value) { @@ -1188,6 +1189,7 @@ protected function evalTextTypeValue($record, $column, $value) /** * Process as number, proxy to text + * @return string */ protected function evalNumberTypeValue($record, $column, $value) { diff --git a/modules/cms/classes/Controller.php b/modules/cms/classes/Controller.php index ab7d57ad41..594e6f5a5c 100644 --- a/modules/cms/classes/Controller.php +++ b/modules/cms/classes/Controller.php @@ -1657,7 +1657,7 @@ protected function verifyCsrfToken() $token = Request::input('_token') ?: Request::header('X-CSRF-TOKEN'); if (!$token && $header = Request::header('X-XSRF-TOKEN')) { - $token = Crypt::decrypt($header); + $token = Crypt::decrypt($header, false); } if (!strlen($token) || !strlen(Session::token())) { From 21947e87ca6b134ed621c884abc3ae78033224ed Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Sat, 2 Nov 2019 15:15:18 +1100 Subject: [PATCH 084/157] Combine common CSRF logic to a trait --- modules/backend/classes/Controller.php | 52 +---------- modules/cms/classes/Controller.php | 68 +------------- modules/system/traits/SecurityController.php | 98 ++++++++++++++++++++ 3 files changed, 100 insertions(+), 118 deletions(-) create mode 100644 modules/system/traits/SecurityController.php diff --git a/modules/backend/classes/Controller.php b/modules/backend/classes/Controller.php index 4d612fa0d9..88ec3ef323 100644 --- a/modules/backend/classes/Controller.php +++ b/modules/backend/classes/Controller.php @@ -36,6 +36,7 @@ class Controller extends ControllerBase use \System\Traits\AssetMaker; use \System\Traits\ConfigMaker; use \System\Traits\EventEmitter; + use \System\Traits\SecurityController; use \Backend\Traits\ErrorMaker; use \Backend\Traits\WidgetMaker; use \October\Rain\Extension\ExtendableTrait; @@ -763,55 +764,4 @@ public function isBackendHintHidden($name) $hiddenHints = UserPreference::forUser()->get('backend::hints.hidden', []); return array_key_exists($name, $hiddenHints); } - - // - // Security - // - - /** - * Checks the request data / headers for a valid CSRF token. - * Returns false if a valid token is not found. Override this - * method to disable the check. - * @return bool - */ - protected function verifyCsrfToken() - { - if (!Config::get('cms.enableCsrfProtection')) { - return true; - } - - if (in_array(Request::method(), ['HEAD', 'GET', 'OPTIONS'])) { - return true; - } - - $token = Request::input('_token') ?: Request::header('X-CSRF-TOKEN'); - - if (!strlen($token) || !strlen(Session::token())) { - return false; - } - - return hash_equals( - Session::token(), - $token - ); - } - - /** - * Checks if the back-end should force a secure protocol (HTTPS) enabled by config. - * @return bool - */ - protected function verifyForceSecure() - { - if (Request::secure() || Request::ajax()) { - return true; - } - - // @todo if year >= 2018 change default from false to null - $forceSecure = Config::get('cms.backendForceSecure', false); - if ($forceSecure === null) { - $forceSecure = !Config::get('app.debug', false); - } - - return !$forceSecure; - } } diff --git a/modules/cms/classes/Controller.php b/modules/cms/classes/Controller.php index 594e6f5a5c..7910e0b89f 100644 --- a/modules/cms/classes/Controller.php +++ b/modules/cms/classes/Controller.php @@ -6,14 +6,12 @@ use View; use Lang; use Flash; -use Crypt; use Config; use Session; use Request; use Response; use Exception; use BackendAuth; -use Carbon\Carbon; use Twig\Environment as TwigEnvironment; use Twig\Cache\FilesystemCache as TwigCacheFilesystem; use Cms\Twig\Loader as TwigLoader; @@ -27,7 +25,6 @@ use October\Rain\Exception\AjaxException; use October\Rain\Exception\ValidationException; use October\Rain\Parse\Bracket as TextParser; -use Symfony\Component\HttpFoundation\Cookie; use Illuminate\Http\RedirectResponse; use Symfony\Component\HttpFoundation\Response as BaseResponse; @@ -42,6 +39,7 @@ class Controller { use \System\Traits\AssetMaker; use \System\Traits\EventEmitter; + use \System\Traits\SecurityController; /** * @var \Cms\Classes\Theme A reference to the CMS theme processed by the controller. @@ -1605,68 +1603,4 @@ protected function setComponentPropertiesFromParams($component, $parameters = [] } } } - - // - // Security - // - - /** - * Adds anti-CSRF cookie. - * Adds a cookie with a token for CSRF checks to the response. - * - * @param BaseResponse $response The response object to add the cookie to - * @return BaseResponse - */ - protected function addXsrfCookie(BaseResponse $response) - { - $config = Config::get('session'); - - $response->headers->setCookie( - new Cookie( - 'XSRF-TOKEN', - Session::token(), - Carbon::now()->addMinutes((int) $config['lifetime'])->getTimestamp(), - $config['path'], - $config['domain'], - $config['secure'], - false, - false, - $config['same_site'] ?? null - ) - ); - - return $response; - } - - /** - * Checks the request data / headers for a valid CSRF token. - * Returns false if a valid token is not found. Override this - * method to disable the check. - * @return bool - */ - protected function verifyCsrfToken() - { - if (!Config::get('cms.enableCsrfProtection', true)) { - return true; - } - - if (in_array(Request::method(), ['HEAD', 'GET', 'OPTIONS'])) { - return true; - } - - $token = Request::input('_token') ?: Request::header('X-CSRF-TOKEN'); - - if (!$token && $header = Request::header('X-XSRF-TOKEN')) { - $token = Crypt::decrypt($header, false); - } - - if (!strlen($token) || !strlen(Session::token())) { - return false; - } - - return hash_equals( - Session::token(), - $token - ); - } } diff --git a/modules/system/traits/SecurityController.php b/modules/system/traits/SecurityController.php new file mode 100644 index 0000000000..7c1d991a35 --- /dev/null +++ b/modules/system/traits/SecurityController.php @@ -0,0 +1,98 @@ +headers->setCookie( + new Cookie( + 'XSRF-TOKEN', + Session::token(), + Carbon::now()->addMinutes((int) $config['lifetime'])->getTimestamp(), + $config['path'], + $config['domain'], + $config['secure'], + false, + false, + $config['same_site'] ?? null + ) + ); + + return $response; + } + + /** + * Checks the request data / headers for a valid CSRF token. + * Returns false if a valid token is not found. Override this + * method to disable the check. + * @return bool + */ + protected function verifyCsrfToken() + { + if (!Config::get('cms.enableCsrfProtection', true)) { + return true; + } + + if (in_array(Request::method(), ['HEAD', 'GET', 'OPTIONS'])) { + return true; + } + + $token = Request::input('_token') ?: Request::header('X-CSRF-TOKEN'); + + if (!$token && $header = Request::header('X-XSRF-TOKEN')) { + $token = Crypt::decrypt($header, false); + } + + if (!strlen($token) || !strlen(Session::token())) { + return false; + } + + return hash_equals( + Session::token(), + $token + ); + } + + /** + * Checks if the back-end should force a secure protocol (HTTPS) enabled by config. + * @return bool + */ + protected function verifyForceSecure() + { + if (Request::secure() || Request::ajax()) { + return true; + } + + // @todo if year >= 2018 change default from false to null + $forceSecure = Config::get('cms.backendForceSecure', false); + if ($forceSecure === null) { + $forceSecure = !Config::get('app.debug', false); + } + + return !$forceSecure; + } +} From ace6e3f922a2ed227181efcc0a6ae2ba41da18c6 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Sat, 2 Nov 2019 16:16:32 +1100 Subject: [PATCH 085/157] Removes double middleware layer For some reason it was decided to allow October controllers to support Laravel middleware, this has been reverted because it is a convoluted solution that doesn't respect the original architecture. There are other ways to handle middleware requirements The original use case appeared to be to simply allow backend controllers to inject headers. This is something easily solvable whilst keeping the simple and original workflow --- modules/backend/classes/BackendController.php | 109 ++---------------- modules/backend/classes/Controller.php | 40 +------ modules/backend/controllers/Auth.php | 40 ++++--- 3 files changed, 40 insertions(+), 149 deletions(-) diff --git a/modules/backend/classes/BackendController.php b/modules/backend/classes/BackendController.php index 24a54465a9..d72cc491c4 100644 --- a/modules/backend/classes/BackendController.php +++ b/modules/backend/classes/BackendController.php @@ -62,44 +62,6 @@ class BackendController extends ControllerBase */ public function __construct() { - $this->middleware(function ($request, $next) { - // Process the request before retrieving controller middleware, to allow for the session and auth data - // to be made available to the controller's constructor. - $response = $next($request); - - // Find requested controller to determine if any middleware has been attached - $pathParts = explode('/', str_replace(Request::root() . '/', '', Request::url())); - if (count($pathParts)) { - // Drop off preceding backend URL part if needed - if (!empty(Config::get('cms.backendUri', 'backend'))) { - array_shift($pathParts); - } - $path = implode('/', $pathParts); - - $requestedController = $this->getRequestedController($path); - if ( - !is_null($requestedController) - && is_array($requestedController) - && count($requestedController['controller']->getMiddleware()) - ) { - $action = $requestedController['action']; - - // Collect applicable middleware and insert middleware into pipeline - $controllerMiddleware = collect($requestedController['controller']->getMiddleware()) - ->reject(function ($data) use ($action) { - return static::methodExcludedByOptions($action, $data['options']); - }) - ->pluck('middleware'); - - foreach ($controllerMiddleware as $middleware) { - $middleware->call($requestedController['controller'], $request, $response); - } - } - } - - return $response; - }); - $this->extendableConstruct(); } @@ -125,7 +87,8 @@ class_exists('\Cms\Classes\Controller') ) { $this->cmsHandling = true; return App::make('Cms\Classes\Controller')->run($url); - } else { + } + else { return Response::make(View::make('backend::404'), 404); } } @@ -158,34 +121,6 @@ public function run($url = null) : $this->passToCmsController($url); } - $controllerRequest = $this->getRequestedController($url); - if (!is_null($controllerRequest)) { - return $controllerRequest['controller']->run( - $controllerRequest['action'], - $controllerRequest['params'] - ); - } - - /* - * Fall back on Cms controller - */ - return $this->passToCmsController($url); - } - - /** - * Determines the controller and action to load in the backend via a provided URL. - * - * If a suitable controller is found, this will return an array with the controller class name as a string, the - * action to call as a string and an array of parameters. If a suitable controller and action cannot be found, - * this method will return null. - * - * @param string $url A URL to determine the requested controller and action for - * @return array|null A suitable controller, action and parameters in an array if found, otherwise null. - */ - protected function getRequestedController($url) - { - $params = RouterHelper::segmentizeUrl($url); - /* * Look for a Module controller */ @@ -199,11 +134,7 @@ protected function getRequestedController($url) $action, base_path().'/modules' )) { - return [ - 'controller' => $controllerObj, - 'action' => $action, - 'params' => $controllerParams - ]; + return $controllerObj->run($action, $controllerParams); } /* @@ -226,15 +157,14 @@ protected function getRequestedController($url) $action, plugins_path() )) { - return [ - 'controller' => $controllerObj, - 'action' => $action, - 'params' => $controllerParams - ]; + return $controllerObj->run($action, $controllerParams); } } - return null; + /* + * Fall back on Cms controller + */ + return $this->passToCmsController($url); } /** @@ -247,10 +177,6 @@ protected function getRequestedController($url) */ protected function findController($controller, $action, $inPath) { - if (isset($this->requestedController)) { - return $this->requestedController; - } - /* * Workaround: Composer does not support case insensitivity. */ @@ -263,16 +189,16 @@ protected function findController($controller, $action, $inPath) } if (!class_exists($controller)) { - return $this->requestedController = null; + return false; } $controllerObj = App::make($controller); if ($controllerObj->actionExists($action)) { - return $this->requestedController = $controllerObj; + return $controllerObj; } - return $this->requestedController = null; + return false; } /** @@ -288,17 +214,4 @@ protected function parseAction($actionName) return $actionName; } - - /** - * Determine if the given options exclude a particular method. - * - * @param string $method - * @param array $options - * @return bool - */ - protected static function methodExcludedByOptions($method, array $options) - { - return (isset($options['only']) && !in_array($method, (array) $options['only'])) || - (!empty($options['except']) && in_array($method, (array) $options['except'])); - } } diff --git a/modules/backend/classes/Controller.php b/modules/backend/classes/Controller.php index 88ec3ef323..027982cbc4 100644 --- a/modules/backend/classes/Controller.php +++ b/modules/backend/classes/Controller.php @@ -19,9 +19,9 @@ use October\Rain\Exception\SystemException; use October\Rain\Exception\ValidationException; use October\Rain\Exception\ApplicationException; +use October\Rain\Extension\Extendable; use Illuminate\Database\Eloquent\MassAssignmentException; use Illuminate\Http\RedirectResponse; -use Illuminate\Routing\Controller as ControllerBase; /** * The Backend base controller class, used by Backend controllers. @@ -30,7 +30,7 @@ * @package october\backend * @author Alexey Bobkov, Samuel Georges */ -class Controller extends ControllerBase +class Controller extends Extendable { use \System\Traits\ViewMaker; use \System\Traits\AssetMaker; @@ -39,12 +39,6 @@ class Controller extends ControllerBase use \System\Traits\SecurityController; use \Backend\Traits\ErrorMaker; use \Backend\Traits\WidgetMaker; - use \October\Rain\Extension\ExtendableTrait; - - /** - * @var array Behaviors implemented by this controller. - */ - public $implement; /** * @var object Reference the logged in admin user. @@ -166,36 +160,6 @@ public function __construct() $manager = new MediaManager($this, 'ocmediamanager'); $manager->bindToController(); } - - $this->extendableConstruct(); - } - - /** - * Extend this object properties upon construction. - */ - public static function extend(Closure $callback) - { - self::extendableExtendCallback($callback); - } - - public function __get($name) - { - return $this->extendableGet($name); - } - - public function __set($name, $value) - { - $this->extendableSet($name, $value); - } - - public function __call($name, $params) - { - return $this->extendableCall($name, $params); - } - - public static function __callStatic($name, $params) - { - return self::extendableCallStatic($name, $params); } /** diff --git a/modules/backend/controllers/Auth.php b/modules/backend/controllers/Auth.php index 1f37a3d063..b02313c873 100644 --- a/modules/backend/controllers/Auth.php +++ b/modules/backend/controllers/Auth.php @@ -3,6 +3,7 @@ use Mail; use Flash; use Backend; +use Request; use Validator; use BackendAuth; use Backend\Models\AccessLog; @@ -34,18 +35,18 @@ public function __construct() { parent::__construct(); - $this->middleware(function ($request, $response) { - // Clear Cache and any previous data to fix Invalid security token issue, see github: #3707 - $response->headers->set('Cache-Control', 'no-cache, no-store, must-revalidate'); - })->only('signin'); - - // Only run on HTTPS connections - if (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] === "on") { - $this->middleware(function ($request, $response) { - // Add HTTP Header 'Clear Site Data' to remove all Sensitive Data when signout, see github issue: #3707 - $response->headers->set('Clear-Site-Data', 'cache, cookies, storage, executionContexts'); - })->only('signout'); - } + // $this->middleware(function ($request, $response) { + // // Clear Cache and any previous data to fix Invalid security token issue, see github: #3707 + // $response->headers->set('Cache-Control', 'no-cache, no-store, must-revalidate'); + // })->only('signin'); + + // // Only run on HTTPS connections + // if (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] === "on") { + // $this->middleware(function ($request, $response) { + // // Add HTTP Header 'Clear Site Data' to remove all Sensitive Data when signout, see github issue: #3707 + // $response->headers->set('Clear-Site-Data', 'cache, cookies, storage, executionContexts'); + // })->only('signout'); + // } $this->layout = 'auth'; } @@ -129,7 +130,14 @@ public function signout() BackendAuth::logout(); } - return Backend::redirect('backend'); + $redirect = Backend::redirect('backend'); + + // Add HTTP Header 'Clear Site Data' to purge all sensitive data upon signout + if (Request::secure()) { + $redirect->header('Clear-Site-Data', 'cache, cookies, storage, executionContexts'); + } + + return $redirect; } /** @@ -146,6 +154,9 @@ public function restore() } } + /** + * Submits the restore form. + */ public function restore_onSubmit() { $rules = [ @@ -202,6 +213,9 @@ public function reset($userId = null, $code = null) $this->vars['id'] = $userId; } + /** + * Submits the reset form. + */ public function reset_onSubmit() { if (!post('id') || !post('code')) { From 63c5c94282dfc03c386f870b891d951147f3365d Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Sat, 2 Nov 2019 16:30:33 +1100 Subject: [PATCH 086/157] Fixes issue where behaviors are not booting --- modules/backend/classes/BackendController.php | 9 +-------- modules/backend/classes/Controller.php | 2 ++ modules/backend/controllers/Auth.php | 8 -------- 3 files changed, 3 insertions(+), 16 deletions(-) diff --git a/modules/backend/classes/BackendController.php b/modules/backend/classes/BackendController.php index d72cc491c4..5043b069e7 100644 --- a/modules/backend/classes/BackendController.php +++ b/modules/backend/classes/BackendController.php @@ -8,10 +8,10 @@ use Config; use Request; use Response; -use Closure; use Illuminate\Routing\Controller as ControllerBase; use October\Rain\Router\Helper as RouterHelper; use System\Classes\PluginManager; +use Closure; /** * This is the master controller for all back-end pages. @@ -50,13 +50,6 @@ class BackendController extends ControllerBase */ protected $cmsHandling = false; - /** - * Stores the requested controller so that the constructor is only run once - * - * @var Backend\Classes\Controller - */ - protected $requestedController; - /** * Instantiate a new BackendController instance. */ diff --git a/modules/backend/classes/Controller.php b/modules/backend/classes/Controller.php index 027982cbc4..1f727432e6 100644 --- a/modules/backend/classes/Controller.php +++ b/modules/backend/classes/Controller.php @@ -153,6 +153,8 @@ public function __construct() */ $this->user = BackendAuth::getUser(); + parent::__construct(); + /* * Media Manager widget is available on all back-end pages */ diff --git a/modules/backend/controllers/Auth.php b/modules/backend/controllers/Auth.php index b02313c873..1c8c4403fe 100644 --- a/modules/backend/controllers/Auth.php +++ b/modules/backend/controllers/Auth.php @@ -40,14 +40,6 @@ public function __construct() // $response->headers->set('Cache-Control', 'no-cache, no-store, must-revalidate'); // })->only('signin'); - // // Only run on HTTPS connections - // if (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] === "on") { - // $this->middleware(function ($request, $response) { - // // Add HTTP Header 'Clear Site Data' to remove all Sensitive Data when signout, see github issue: #3707 - // $response->headers->set('Clear-Site-Data', 'cache, cookies, storage, executionContexts'); - // })->only('signout'); - // } - $this->layout = 'auth'; } From 14123a5bf3ee2a79925f605f333519417b318938 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Sat, 2 Nov 2019 18:21:22 +1100 Subject: [PATCH 087/157] Move response common functions to ResponseMaker trait --- modules/backend/classes/Controller.php | 48 +++-------------- modules/cms/classes/Controller.php | 41 +++----------- modules/system/traits/ResponseMaker.php | 72 +++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 74 deletions(-) create mode 100644 modules/system/traits/ResponseMaker.php diff --git a/modules/backend/classes/Controller.php b/modules/backend/classes/Controller.php index 1f727432e6..05d4eb563f 100644 --- a/modules/backend/classes/Controller.php +++ b/modules/backend/classes/Controller.php @@ -36,6 +36,7 @@ class Controller extends Extendable use \System\Traits\AssetMaker; use \System\Traits\ConfigMaker; use \System\Traits\EventEmitter; + use \System\Traits\ResponseMaker; use \System\Traits\SecurityController; use \Backend\Traits\ErrorMaker; use \Backend\Traits\WidgetMaker; @@ -108,16 +109,6 @@ class Controller extends Extendable */ protected $guarded = []; - /** - * @var int Response status code - */ - protected $statusCode = 200; - - /** - * @var mixed Override the standard controller response. - */ - protected $responseOverride = null; - /** * Constructor. */ @@ -177,6 +168,7 @@ public function run($action = null, $params = []) /* * Check security token. + * @see \System\Traits\SecurityController */ if (!$this->verifyCsrfToken()) { return Response::make(Lang::get('system::lang.page.invalid_token.label'), 403); @@ -184,6 +176,7 @@ public function run($action = null, $params = []) /* * Check forced HTTPS protocol. + * @see \System\Traits\SecurityController */ if (!$this->verifyForceSecure()) { return Redirect::secure(Request::path()); @@ -251,15 +244,11 @@ public function run($action = null, $params = []) */ $result = $this->execPageAction($action, $params); - if ($this->responseOverride !== null) { - $result = $this->responseOverride; - } - - if (!is_string($result)) { - return $result; - } - - return Response::make($result, $this->statusCode); + /* + * Prepare and return response + * @see \System\Traits\ResponseMaker + */ + return $this->makeResponse($result); } /** @@ -649,27 +638,6 @@ public function getId($suffix = null) return $id; } - /** - * Sets the status code for the current web response. - * @param int $code Status code - */ - public function setStatusCode($code) - { - $this->statusCode = (int) $code; - return $this; - } - - /** - * Sets the response for the current page request cycle, this value takes priority - * over the standard response prepared by the controller. - * @param mixed $response Response object or string - */ - public function setResponse($response) - { - $this->responseOverride = $response; - return $this; - } - // // Hints // diff --git a/modules/cms/classes/Controller.php b/modules/cms/classes/Controller.php index 7910e0b89f..53293d70e8 100644 --- a/modules/cms/classes/Controller.php +++ b/modules/cms/classes/Controller.php @@ -39,6 +39,7 @@ class Controller { use \System\Traits\AssetMaker; use \System\Traits\EventEmitter; + use \System\Traits\ResponseMaker; use \System\Traits\SecurityController; /** @@ -91,11 +92,6 @@ class Controller */ public $vars = []; - /** - * @var int Response status code - */ - protected $statusCode = 200; - /** * @var self Cache of self */ @@ -174,6 +170,7 @@ protected function runInternal($url = '/') /* * Check security token. + * @see \System\Traits\SecurityController */ if (!$this->verifyCsrfToken()) { return Response::make(Lang::get('system::lang.page.invalid_token.label'), 403); @@ -284,11 +281,11 @@ protected function runInternal($url = '/') return $event; } - if (!is_string($result)) { - return $result; - } - - return Response::make($result, $this->statusCode); + /* + * Prepare and return response + * @see \System\Traits\ResponseMaker + */ + return $this->makeResponse($result); } /** @@ -1251,34 +1248,10 @@ public function renderComponent($name, $parameters = []) return $result; } - // - // Setters - // - - /** - * Sets the status code for the current web response. - * @param int $code Status code - * @return self - */ - public function setStatusCode($code) - { - $this->statusCode = (int) $code; - return $this; - } - // // Getters // - /** - * Returns the status code for the current web response. - * @return int Status code - */ - public function getStatusCode() - { - return $this->statusCode; - } - /** * Returns an existing instance of the controller. * If the controller doesn't exists, returns null. diff --git a/modules/system/traits/ResponseMaker.php b/modules/system/traits/ResponseMaker.php new file mode 100644 index 0000000000..9aa4bed4de --- /dev/null +++ b/modules/system/traits/ResponseMaker.php @@ -0,0 +1,72 @@ +statusCode = (int) $code; + return $this; + } + + /** + * Returns the status code for the current web response. + * @return int Status code + */ + public function getStatusCode() + { + return $this->statusCode; + } + + /** + * Sets the response for the current page request cycle, this value takes priority + * over the standard response prepared by the controller. + * @param mixed $response Response object or string + */ + public function setResponse($response) + { + $this->responseOverride = $response; + return $this; + } + + /** + * Prepares a response that considers overrides and custom responses. + * @param mixed $contents + * @return mixed + */ + public function makeResponse($contents) + { + if ($this->responseOverride !== null) { + $contents = $this->responseOverride; + } + + if (!is_string($contents)) { + return $contents; + } + + return Response::make($contents, $this->statusCode); + } +} From ac1063f54e688217e6467ea2a86eab7b73cea2e6 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Sat, 2 Nov 2019 18:57:32 +1100 Subject: [PATCH 088/157] Add header and cookie support to ResponseMaker --- modules/backend/controllers/Auth.php | 14 +++--- modules/system/traits/ResponseMaker.php | 60 +++++++++++++++++++++++-- 2 files changed, 61 insertions(+), 13 deletions(-) diff --git a/modules/backend/controllers/Auth.php b/modules/backend/controllers/Auth.php index 1c8c4403fe..7bd8d59acb 100644 --- a/modules/backend/controllers/Auth.php +++ b/modules/backend/controllers/Auth.php @@ -35,11 +35,6 @@ public function __construct() { parent::__construct(); - // $this->middleware(function ($request, $response) { - // // Clear Cache and any previous data to fix Invalid security token issue, see github: #3707 - // $response->headers->set('Cache-Control', 'no-cache, no-store, must-revalidate'); - // })->only('signin'); - $this->layout = 'auth'; } @@ -58,6 +53,9 @@ public function signin() { $this->bodyClass = 'signin'; + // Clear Cache and any previous data to fix invalid security token issue + $this->setResponseHeader('Cache-Control', 'no-cache, no-store, must-revalidate'); + try { if (post('postback')) { return $this->signin_onSubmit(); @@ -122,14 +120,12 @@ public function signout() BackendAuth::logout(); } - $redirect = Backend::redirect('backend'); - // Add HTTP Header 'Clear Site Data' to purge all sensitive data upon signout if (Request::secure()) { - $redirect->header('Clear-Site-Data', 'cache, cookies, storage, executionContexts'); + $this->setResponseHeader('Clear-Site-Data', 'cache, cookies, storage, executionContexts'); } - return $redirect; + return Backend::redirect('backend'); } /** diff --git a/modules/system/traits/ResponseMaker.php b/modules/system/traits/ResponseMaker.php index 9aa4bed4de..a4c9ff1deb 100644 --- a/modules/system/traits/ResponseMaker.php +++ b/modules/system/traits/ResponseMaker.php @@ -1,6 +1,8 @@ responseHeaderBag === null) { + $this->responseHeaderBag = new HeaderBag; + } + + $this->responseHeaderBag->set($key, $values, $replace); + + return $this; + } + + /** + * Add a cookie to the response. + * + * @param \Symfony\Component\HttpFoundation\Cookie|mixed $cookie + * @return $this + */ + public function setResponseCookie($cookie) + { + if ($this->responseHeaderBag === null) { + $this->responseHeaderBag = new HeaderBag; + } + + if (is_string($cookie) && function_exists('cookie')) { + $cookie = call_user_func_array('cookie', func_get_args()); + } + + $this->responseHeaderBag->setCookie($cookie); + + return $this; + } + /** * Prepares a response that considers overrides and custom responses. * @param mixed $contents @@ -63,10 +111,14 @@ public function makeResponse($contents) $contents = $this->responseOverride; } - if (!is_string($contents)) { - return $contents; + if (is_string($contents)) { + $contents = Response::make($contents, $this->statusCode); + } + + if ($contents instanceof BaseResponse && $this->responseHeaderBag !== null) { + $contents = $contents->withHeaders($this->responseHeaderBag); } - return Response::make($contents, $this->statusCode); + return $contents; } } From 6beb22570a16774c5e6197f88c93a38bf7495374 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Sat, 2 Nov 2019 19:14:45 +1100 Subject: [PATCH 089/157] Add XSRF to backend, simplify CMS controller run() method runInternal has been removed because we do not want to blanket our response logic over every single response, only the happy path. This is because it is impossible to remove. So it is better to take the inverted approach, where if you want the CMS' headers in your custom response, add them yourself. This becomes easy via the new makeResponse() method --- modules/backend/classes/Controller.php | 7 +++++ modules/cms/classes/Controller.php | 28 +++++-------------- modules/system/traits/ResponseMaker.php | 26 +++++++++++++----- modules/system/traits/SecurityController.php | 29 ++++++++------------ 4 files changed, 45 insertions(+), 45 deletions(-) diff --git a/modules/backend/classes/Controller.php b/modules/backend/classes/Controller.php index 05d4eb563f..fe929add1a 100644 --- a/modules/backend/classes/Controller.php +++ b/modules/backend/classes/Controller.php @@ -174,6 +174,13 @@ public function run($action = null, $params = []) return Response::make(Lang::get('system::lang.page.invalid_token.label'), 403); } + if ( + Config::get('cms.enableCsrfProtection', true) && + Config::get('cms.enableXsrfCookies', true) + ) { + $this->setResponseCookie($this->makeXsrfCookie()); + } + /* * Check forced HTTPS protocol. * @see \System\Traits\SecurityController diff --git a/modules/cms/classes/Controller.php b/modules/cms/classes/Controller.php index 53293d70e8..0e2a38da27 100644 --- a/modules/cms/classes/Controller.php +++ b/modules/cms/classes/Controller.php @@ -138,27 +138,6 @@ public function __construct($theme = null) * @return BaseResponse Returns the response to the provided URL */ public function run($url = '/') - { - $response = $this->runInternal($url); - - if ( - Config::get('cms.enableCsrfProtection', true) && - Config::get('cms.enableXsrfCookies', true) && - $response instanceof BaseResponse - ) { - $this->addXsrfCookie($response); - } - - return $response; - } - - /** - * Process the request internally - * - * @param string $url Specifies the requested page URL. - * @return BaseResponse Returns the response to the provided URL - */ - protected function runInternal($url = '/') { if ($url === null) { $url = Request::path(); @@ -176,6 +155,13 @@ protected function runInternal($url = '/') return Response::make(Lang::get('system::lang.page.invalid_token.label'), 403); } + if ( + Config::get('cms.enableCsrfProtection', true) && + Config::get('cms.enableXsrfCookies', true) + ) { + $this->setResponseCookie($this->makeXsrfCookie()); + } + /* * Hidden page */ diff --git a/modules/system/traits/ResponseMaker.php b/modules/system/traits/ResponseMaker.php index a4c9ff1deb..f9690c9100 100644 --- a/modules/system/traits/ResponseMaker.php +++ b/modules/system/traits/ResponseMaker.php @@ -1,7 +1,7 @@ statusCode = (int) $code; + return $this; } @@ -57,6 +58,7 @@ public function getStatusCode() public function setResponse($response) { $this->responseOverride = $response; + return $this; } @@ -71,7 +73,7 @@ public function setResponse($response) public function setResponseHeader($key, $values, $replace = true) { if ($this->responseHeaderBag === null) { - $this->responseHeaderBag = new HeaderBag; + $this->responseHeaderBag = new ResponseHeaderBag; } $this->responseHeaderBag->set($key, $values, $replace); @@ -88,7 +90,7 @@ public function setResponseHeader($key, $values, $replace = true) public function setResponseCookie($cookie) { if ($this->responseHeaderBag === null) { - $this->responseHeaderBag = new HeaderBag; + $this->responseHeaderBag = new ResponseHeaderBag; } if (is_string($cookie) && function_exists('cookie')) { @@ -100,6 +102,15 @@ public function setResponseCookie($cookie) return $this; } + /** + * Get the header response bag + * @return Symfony\Component\HttpFoundation\ResponseHeaderBag|null + */ + public function getResponseHeaders() + { + return $this->responseHeaderBag; + } + /** * Prepares a response that considers overrides and custom responses. * @param mixed $contents @@ -112,11 +123,12 @@ public function makeResponse($contents) } if (is_string($contents)) { - $contents = Response::make($contents, $this->statusCode); + $contents = Response::make($contents, $this->getStatusCode()); } - if ($contents instanceof BaseResponse && $this->responseHeaderBag !== null) { - $contents = $contents->withHeaders($this->responseHeaderBag); + $responseHeaders = $this->getResponseHeaders(); + if ($responseHeaders && $contents instanceof BaseResponse) { + $contents = $contents->withHeaders($responseHeaders); } return $contents; diff --git a/modules/system/traits/SecurityController.php b/modules/system/traits/SecurityController.php index 7c1d991a35..d96a7ca16d 100644 --- a/modules/system/traits/SecurityController.php +++ b/modules/system/traits/SecurityController.php @@ -21,28 +21,23 @@ trait SecurityController * Adds anti-CSRF cookie. * Adds a cookie with a token for CSRF checks to the response. * - * @param BaseResponse $response The response object to add the cookie to - * @return BaseResponse + * @return \Symfony\Component\HttpFoundation\Cookie */ - protected function addXsrfCookie(BaseResponse $response) + protected function makeXsrfCookie() { $config = Config::get('session'); - $response->headers->setCookie( - new Cookie( - 'XSRF-TOKEN', - Session::token(), - Carbon::now()->addMinutes((int) $config['lifetime'])->getTimestamp(), - $config['path'], - $config['domain'], - $config['secure'], - false, - false, - $config['same_site'] ?? null - ) + return new Cookie( + 'XSRF-TOKEN', + Session::token(), + Carbon::now()->addMinutes((int) $config['lifetime'])->getTimestamp(), + $config['path'], + $config['domain'], + $config['secure'], + false, + false, + $config['same_site'] ?? null ); - - return $response; } /** From 4b7e421f11e9772171f7c9a54d89860816ad5b02 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Sat, 2 Nov 2019 19:42:09 +1100 Subject: [PATCH 090/157] Remove unused import --- modules/cms/classes/Controller.php | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/cms/classes/Controller.php b/modules/cms/classes/Controller.php index 0e2a38da27..13e6115729 100644 --- a/modules/cms/classes/Controller.php +++ b/modules/cms/classes/Controller.php @@ -26,7 +26,6 @@ use October\Rain\Exception\ValidationException; use October\Rain\Parse\Bracket as TextParser; use Illuminate\Http\RedirectResponse; -use Symfony\Component\HttpFoundation\Response as BaseResponse; /** * The CMS controller class. From 380df1b7969773e8b26400c6195908ffca4fba61 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Sun, 3 Nov 2019 08:02:28 +1100 Subject: [PATCH 091/157] Apply ResponseMaker to backend AJAX and cms.page.display event --- modules/backend/classes/Controller.php | 12 ++++++------ modules/cms/classes/Controller.php | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/backend/classes/Controller.php b/modules/backend/classes/Controller.php index fe929add1a..a80b5b4ddd 100644 --- a/modules/backend/classes/Controller.php +++ b/modules/backend/classes/Controller.php @@ -232,24 +232,24 @@ public function run($action = null, $params = []) * Execute AJAX event */ if ($ajaxResponse = $this->execAjaxHandlers()) { - return $ajaxResponse; + $result = $ajaxResponse; } - /* * Execute postback handler */ - if ( + elseif ( ($handler = post('_handler')) && ($handlerResponse = $this->runAjaxHandler($handler)) && $handlerResponse !== true ) { - return $handlerResponse; + $result = $handlerResponse; } - /* * Execute page action */ - $result = $this->execPageAction($action, $params); + else { + $result = $this->execPageAction($action, $params); + } /* * Prepare and return response diff --git a/modules/cms/classes/Controller.php b/modules/cms/classes/Controller.php index 13e6115729..9c1e05b11b 100644 --- a/modules/cms/classes/Controller.php +++ b/modules/cms/classes/Controller.php @@ -263,7 +263,7 @@ public function run($url = '/') * */ if ($event = $this->fireSystemEvent('cms.page.display', [$url, $page, $result])) { - return $event; + $result = $event; } /* From b61142dedbfa691c3124504e346c302c79619378 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Mon, 4 Nov 2019 09:06:05 +1100 Subject: [PATCH 092/157] Remove XSRF cookie This was a contentious change is generally a bad idea to blanket all requests with a dependant cookie. We will try something else. Revert enableXsrfCookies setting. Fixes UX issue introduced where the token expires. This should be replaced by a CSRF policy that determines whether this is needed on the front end. --- config/cms.php | 13 ------------- modules/backend/classes/Controller.php | 7 ------- modules/cms/classes/Controller.php | 12 ++++-------- 3 files changed, 4 insertions(+), 28 deletions(-) diff --git a/config/cms.php b/config/cms.php index 5c885e220d..acb98db9a4 100644 --- a/config/cms.php +++ b/config/cms.php @@ -381,19 +381,6 @@ 'enableCsrfProtection' => true, - /* - |-------------------------------------------------------------------------- - | Automatic XSRF Cookies - |-------------------------------------------------------------------------- - | - | Automatically provide and process an XSRF cookie to the browser to - | support CSRF protection on all AJAX requests without having to add - | an explicit CSRF token to the frontend markup - | - */ - - 'enableXsrfCookies' => true, - /* |-------------------------------------------------------------------------- | Force bytecode invalidation diff --git a/modules/backend/classes/Controller.php b/modules/backend/classes/Controller.php index a80b5b4ddd..ff6177320e 100644 --- a/modules/backend/classes/Controller.php +++ b/modules/backend/classes/Controller.php @@ -174,13 +174,6 @@ public function run($action = null, $params = []) return Response::make(Lang::get('system::lang.page.invalid_token.label'), 403); } - if ( - Config::get('cms.enableCsrfProtection', true) && - Config::get('cms.enableXsrfCookies', true) - ) { - $this->setResponseCookie($this->makeXsrfCookie()); - } - /* * Check forced HTTPS protocol. * @see \System\Traits\SecurityController diff --git a/modules/cms/classes/Controller.php b/modules/cms/classes/Controller.php index 9c1e05b11b..777a891475 100644 --- a/modules/cms/classes/Controller.php +++ b/modules/cms/classes/Controller.php @@ -148,19 +148,15 @@ public function run($url = '/') /* * Check security token. + * + * Note: Ignore AJAX requests until a CSRF policy introduced. + * * @see \System\Traits\SecurityController */ - if (!$this->verifyCsrfToken()) { + if (!Request::ajax() && !$this->verifyCsrfToken()) { return Response::make(Lang::get('system::lang.page.invalid_token.label'), 403); } - if ( - Config::get('cms.enableCsrfProtection', true) && - Config::get('cms.enableXsrfCookies', true) - ) { - $this->setResponseCookie($this->makeXsrfCookie()); - } - /* * Hidden page */ From 61ef73f53a8269d37ea3c1850938d10a556265e5 Mon Sep 17 00:00:00 2001 From: Ben Thomson Date: Wed, 6 Nov 2019 17:44:46 +0800 Subject: [PATCH 093/157] Fix empty Richeditor class lists from breaking widget (#4725) --- modules/backend/formwidgets/RichEditor.php | 13 ++++++++++++- .../formwidgets/richeditor/partials/_richeditor.htm | 10 +++++----- modules/backend/models/EditorSetting.php | 13 +++++++++---- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/modules/backend/formwidgets/RichEditor.php b/modules/backend/formwidgets/RichEditor.php index af905d6fcd..c236ca754f 100644 --- a/modules/backend/formwidgets/RichEditor.php +++ b/modules/backend/formwidgets/RichEditor.php @@ -1,10 +1,12 @@ addCss('css/richeditor.css', 'core'); $this->addJs('js/build-min.js', 'core'); - $this->addJs('js/build-plugins-min.js', 'core'); + + if (Config::get('develop.decompileBackendAssets', false)) { + $scripts = Backend::decompileAsset($this->getAssetPath('js/build-plugins.js')); + foreach ($scripts as $script) { + $this->addJs($script, 'core'); + } + } else { + $this->addJs('js/build-plugins-min.js', 'core'); + } + $this->addJs('/modules/backend/formwidgets/codeeditor/assets/js/build-min.js', 'core'); if ($lang = $this->getValidEditorLang()) { diff --git a/modules/backend/formwidgets/richeditor/partials/_richeditor.htm b/modules/backend/formwidgets/richeditor/partials/_richeditor.htm index 31f2b2646a..5b7d0c63c9 100755 --- a/modules/backend/formwidgets/richeditor/partials/_richeditor.htm +++ b/modules/backend/formwidgets/richeditor/partials/_richeditor.htm @@ -16,11 +16,11 @@ data-no-wrap-tags="" data-remove-tags="" data-line-breaker-tags="" - data-image-styles="" - data-link-styles="" - data-paragraph-styles="" - data-table-styles="" - data-table-cell-styles="" + data-image-styles="" + data-link-styles="" + data-paragraph-styles="" + data-table-styles="" + data-table-cell-styles="" data-links-handler="getEventHandler('onLoadPageLinksForm') ?>" data-ace-vendor-path="" data-control="richeditor"> diff --git a/modules/backend/models/EditorSetting.php b/modules/backend/models/EditorSetting.php index 4fda96bcf7..25510db843 100644 --- a/modules/backend/models/EditorSetting.php +++ b/modules/backend/models/EditorSetting.php @@ -33,7 +33,7 @@ class EditorSetting extends Model * @var mixed Settings form field defitions */ public $settingsFields = 'fields.yaml'; - + /** * @var string The key to store rendered CSS in the cache under */ @@ -128,9 +128,14 @@ public static function getConfiguredStyles($key, $default = null) $defaultValue = $instance->getDefaultValue($key); if (is_array($value)) { - $value = array_build($value, function ($key, $value) { - return [array_get($value, 'class_name'), array_get($value, 'class_label')]; - }); + $value = array_filter(array_build($value, function ($key, $value) { + if (array_has($value, ['class_name', 'class_label'])) { + return [ + array_get($value, 'class_name'), + array_get($value, 'class_label') + ]; + } + })); } return $value != $defaultValue ? $value : $default; From 892a1575b0279aeb9b0ec9aaad1a20ccacd278a2 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Wed, 6 Nov 2019 16:55:16 -0600 Subject: [PATCH 094/157] Fixed typo --- modules/system/assets/ui/js/chart.line.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/system/assets/ui/js/chart.line.js b/modules/system/assets/ui/js/chart.line.js index ee41bedfa9..208b0e51da 100644 --- a/modules/system/assets/ui/js/chart.line.js +++ b/modules/system/assets/ui/js/chart.line.js @@ -80,7 +80,7 @@ var parsedOptions = {} try { - parsedOptions = ocJSON("{" + value + "}"); + parsedOptions = ocJSON("{" + options.chartOptions + "}"); } catch (e) { throw new Error('Error parsing the data-chart-options attribute value. '+e); } From 39255fbf1ec0030c0c9ca263ea0402a802d2564c Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Wed, 6 Nov 2019 16:56:46 -0600 Subject: [PATCH 095/157] minor formatting fix --- modules/backend/classes/BackendController.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/backend/classes/BackendController.php b/modules/backend/classes/BackendController.php index 5043b069e7..57ac5dff2e 100644 --- a/modules/backend/classes/BackendController.php +++ b/modules/backend/classes/BackendController.php @@ -80,8 +80,7 @@ class_exists('\Cms\Classes\Controller') ) { $this->cmsHandling = true; return App::make('Cms\Classes\Controller')->run($url); - } - else { + } else { return Response::make(View::make('backend::404'), 404); } } From 00779a1e7cd3fd4e65bac9fbf4978e9d63c17335 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Thu, 7 Nov 2019 11:59:00 -0600 Subject: [PATCH 096/157] Restore middleware support in backend controllers. Reverts https://github.com/octobercms/october/commit/f73d8e6d498a211192976a525016b4a961707e3f. While there are other ways to achieve some of the same end results, this code existed in the code base for 8 months without issues and is included in the official docs. This means that there could be devs that are depending on this behavior. Additionally, while this may make the internal logic to the BackendController class more complex, it simplifies the developer experience by bringing the Backend\Classes\Controller base class more in line with the standard Laravel controller class. --- modules/backend/classes/BackendController.php | 106 ++++++++++++++++-- modules/backend/classes/Controller.php | 36 +++++- 2 files changed, 131 insertions(+), 11 deletions(-) diff --git a/modules/backend/classes/BackendController.php b/modules/backend/classes/BackendController.php index 57ac5dff2e..dcf590be2e 100644 --- a/modules/backend/classes/BackendController.php +++ b/modules/backend/classes/BackendController.php @@ -55,6 +55,44 @@ class BackendController extends ControllerBase */ public function __construct() { + $this->middleware(function ($request, $next) { + // Process the request before retrieving controller middleware, to allow for the session and auth data + // to be made available to the controller's constructor. + $response = $next($request); + + // Find requested controller to determine if any middleware has been attached + $pathParts = explode('/', str_replace(Request::root() . '/', '', Request::url())); + if (count($pathParts)) { + // Drop off preceding backend URL part if needed + if (!empty(Config::get('cms.backendUri', 'backend'))) { + array_shift($pathParts); + } + $path = implode('/', $pathParts); + + $requestedController = $this->getRequestedController($path); + if ( + !is_null($requestedController) + && is_array($requestedController) + && count($requestedController['controller']->getMiddleware()) + ) { + $action = $requestedController['action']; + + // Collect applicable middleware and insert middleware into pipeline + $controllerMiddleware = collect($requestedController['controller']->getMiddleware()) + ->reject(function ($data) use ($action) { + return static::methodExcludedByOptions($action, $data['options']); + }) + ->pluck('middleware'); + + foreach ($controllerMiddleware as $middleware) { + $middleware->call($requestedController['controller'], $request, $response); + } + } + } + + return $response; + }); + $this->extendableConstruct(); } @@ -113,6 +151,34 @@ public function run($url = null) : $this->passToCmsController($url); } + $controllerRequest = $this->getRequestedController($url); + if (!is_null($controllerRequest)) { + return $controllerRequest['controller']->run( + $controllerRequest['action'], + $controllerRequest['params'] + ); + } + + /* + * Fall back on Cms controller + */ + return $this->passToCmsController($url); + } + + /** + * Determines the controller and action to load in the backend via a provided URL. + * + * If a suitable controller is found, this will return an array with the controller class name as a string, the + * action to call as a string and an array of parameters. If a suitable controller and action cannot be found, + * this method will return null. + * + * @param string $url A URL to determine the requested controller and action for + * @return array|null A suitable controller, action and parameters in an array if found, otherwise null. + */ + protected function getRequestedController($url) + { + $params = RouterHelper::segmentizeUrl($url); + /* * Look for a Module controller */ @@ -126,7 +192,11 @@ public function run($url = null) $action, base_path().'/modules' )) { - return $controllerObj->run($action, $controllerParams); + return [ + 'controller' => $controllerObj, + 'action' => $action, + 'params' => $controllerParams + ]; } /* @@ -149,14 +219,15 @@ public function run($url = null) $action, plugins_path() )) { - return $controllerObj->run($action, $controllerParams); + return [ + 'controller' => $controllerObj, + 'action' => $action, + 'params' => $controllerParams + ]; } } - /* - * Fall back on Cms controller - */ - return $this->passToCmsController($url); + return null; } /** @@ -169,6 +240,10 @@ public function run($url = null) */ protected function findController($controller, $action, $inPath) { + if (isset($this->requestedController)) { + return $this->requestedController; + } + /* * Workaround: Composer does not support case insensitivity. */ @@ -181,16 +256,16 @@ protected function findController($controller, $action, $inPath) } if (!class_exists($controller)) { - return false; + return $this->requestedController = null; } $controllerObj = App::make($controller); if ($controllerObj->actionExists($action)) { - return $controllerObj; + return $this->requestedController = $controllerObj; } - return false; + return $this->requestedController = null; } /** @@ -206,4 +281,17 @@ protected function parseAction($actionName) return $actionName; } + + /** + * Determine if the given options exclude a particular method. + * + * @param string $method + * @param array $options + * @return bool + */ + protected static function methodExcludedByOptions($method, array $options) + { + return (isset($options['only']) && !in_array($method, (array) $options['only'])) || + (!empty($options['except']) && in_array($method, (array) $options['except'])); + } } diff --git a/modules/backend/classes/Controller.php b/modules/backend/classes/Controller.php index ff6177320e..9d4dc79957 100644 --- a/modules/backend/classes/Controller.php +++ b/modules/backend/classes/Controller.php @@ -19,9 +19,9 @@ use October\Rain\Exception\SystemException; use October\Rain\Exception\ValidationException; use October\Rain\Exception\ApplicationException; -use October\Rain\Extension\Extendable; use Illuminate\Database\Eloquent\MassAssignmentException; use Illuminate\Http\RedirectResponse; +use Illuminate\Routing\Controller as ControllerBase; /** * The Backend base controller class, used by Backend controllers. @@ -30,7 +30,7 @@ * @package october\backend * @author Alexey Bobkov, Samuel Georges */ -class Controller extends Extendable +class Controller extends ControllerBase { use \System\Traits\ViewMaker; use \System\Traits\AssetMaker; @@ -40,6 +40,12 @@ class Controller extends Extendable use \System\Traits\SecurityController; use \Backend\Traits\ErrorMaker; use \Backend\Traits\WidgetMaker; + use \October\Rain\Extension\ExtendableTrait; + + /** + * @var array Behaviors implemented by this controller. + */ + public $implement; /** * @var object Reference the logged in admin user. @@ -153,6 +159,32 @@ public function __construct() $manager = new MediaManager($this, 'ocmediamanager'); $manager->bindToController(); } + + $this->extendableConstruct(); + } + + /** + * Extend this object properties upon construction. + */ + public static function extend(Closure $callback) + { + self::extendableExtendCallback($callback); + } + public function __get($name) + { + return $this->extendableGet($name); + } + public function __set($name, $value) + { + $this->extendableSet($name, $value); + } + public function __call($name, $params) + { + return $this->extendableCall($name, $params); + } + public static function __callStatic($name, $params) + { + return self::extendableCallStatic($name, $params); } /** From 62ad3572a519c4e6431789f2172d5a4c6a2d23bf Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Thu, 7 Nov 2019 12:03:10 -0600 Subject: [PATCH 097/157] cleanup from last commit --- modules/backend/classes/BackendController.php | 7 +++++++ modules/backend/classes/Controller.php | 6 ++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/modules/backend/classes/BackendController.php b/modules/backend/classes/BackendController.php index dcf590be2e..481df7ae11 100644 --- a/modules/backend/classes/BackendController.php +++ b/modules/backend/classes/BackendController.php @@ -50,6 +50,13 @@ class BackendController extends ControllerBase */ protected $cmsHandling = false; + /** + * Stores the requested controller so that the constructor is only run once + * + * @var Backend\Classes\Controller + */ + protected $requestedController; + /** * Instantiate a new BackendController instance. */ diff --git a/modules/backend/classes/Controller.php b/modules/backend/classes/Controller.php index 9d4dc79957..d019150cbd 100644 --- a/modules/backend/classes/Controller.php +++ b/modules/backend/classes/Controller.php @@ -150,8 +150,6 @@ public function __construct() */ $this->user = BackendAuth::getUser(); - parent::__construct(); - /* * Media Manager widget is available on all back-end pages */ @@ -170,18 +168,22 @@ public static function extend(Closure $callback) { self::extendableExtendCallback($callback); } + public function __get($name) { return $this->extendableGet($name); } + public function __set($name, $value) { $this->extendableSet($name, $value); } + public function __call($name, $params) { return $this->extendableCall($name, $params); } + public static function __callStatic($name, $params) { return self::extendableCallStatic($name, $params); From 421854a871b73974061ba2f5919802839edb5a48 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Thu, 7 Nov 2019 12:14:32 -0600 Subject: [PATCH 098/157] Change default of cms.backendForceSecure to reflect the config default that's been in place since 2016. --- modules/system/traits/SecurityController.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/system/traits/SecurityController.php b/modules/system/traits/SecurityController.php index d96a7ca16d..66da07ee86 100644 --- a/modules/system/traits/SecurityController.php +++ b/modules/system/traits/SecurityController.php @@ -82,8 +82,7 @@ protected function verifyForceSecure() return true; } - // @todo if year >= 2018 change default from false to null - $forceSecure = Config::get('cms.backendForceSecure', false); + $forceSecure = Config::get('cms.backendForceSecure', null); if ($forceSecure === null) { $forceSecure = !Config::get('app.debug', false); } From 627c7ee386386b075d427e30789fafdbfe2eeeea Mon Sep 17 00:00:00 2001 From: Christophe Vuagniaux Date: Sun, 10 Nov 2019 17:52:36 +0100 Subject: [PATCH 099/157] Avoid array_intersect error if argv is not defined (#4751) Credit to @ChVuagniaux. Can be triggered when attempting to run Laravel HTTP tests on OctoberCMS (https://laravel.com/docs/6.x/http-tests) --- modules/system/ServiceProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/system/ServiceProvider.php b/modules/system/ServiceProvider.php index eee21aeb81..fa729eb5a6 100644 --- a/modules/system/ServiceProvider.php +++ b/modules/system/ServiceProvider.php @@ -153,7 +153,7 @@ protected function registerPrivilegedActions() /* * CLI */ - if (App::runningInConsole() && count(array_intersect($commands, Request::server('argv'))) > 0) { + if (App::runningInConsole() && count(array_intersect($commands, Request::server('argv', []))) > 0) { PluginManager::$noInit = true; } } From 34a87c59a0ae439ce655919f9f69645bbfc68340 Mon Sep 17 00:00:00 2001 From: Tomasz Strojny Date: Mon, 11 Nov 2019 19:34:58 +0100 Subject: [PATCH 100/157] Removed double checking if file is protected in FileUpload widget (#4753) Credit to @tomaszstrojny. Cleanup from https://github.com/octobercms/october/commit/4f7c5cc1e753817beda9b9c914d7d8b28b00dd2c. --- modules/backend/formwidgets/FileUpload.php | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/modules/backend/formwidgets/FileUpload.php b/modules/backend/formwidgets/FileUpload.php index 89e2d3e574..3a6cb23282 100644 --- a/modules/backend/formwidgets/FileUpload.php +++ b/modules/backend/formwidgets/FileUpload.php @@ -8,7 +8,6 @@ use Backend\Widgets\Form; use Backend\Classes\FormField; use Backend\Classes\FormWidgetBase; -use Backend\Controllers\Files as FilesController; use October\Rain\Filesystem\Definitions as FileDefinitions; use ApplicationException; use ValidationException; @@ -497,25 +496,10 @@ public function onUpload() */ protected function decorateFileAttributes($file) { - /* - * File is protected, create a secure public path - */ - if (!$file->isPublic()) { - $path = $thumb = FilesController::getDownloadUrl($file); + $path = $thumb = $file->getPath(); - if ($this->imageWidth || $this->imageHeight) { - $thumb = FilesController::getThumbUrl($file, $this->imageWidth, $this->imageHeight, $this->thumbOptions); - } - } - /* - * Otherwise use public paths - */ - else { - $path = $thumb = $file->getPath(); - - if ($this->imageWidth || $this->imageHeight) { - $thumb = $file->getThumb($this->imageWidth, $this->imageHeight, $this->thumbOptions); - } + if ($this->imageWidth || $this->imageHeight) { + $thumb = $file->getThumb($this->imageWidth, $this->imageHeight, $this->thumbOptions); } $file->pathUrl = $path; From d9d7b7dec315bc53ff0bc709c2e5a1c2b44319b3 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Tue, 12 Nov 2019 12:32:17 -0600 Subject: [PATCH 101/157] Check user permission for the mediafinder formwidget. Fixes #4216. Replaces #4669. Credit to @gergo85. --- modules/backend/formwidgets/MediaFinder.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/backend/formwidgets/MediaFinder.php b/modules/backend/formwidgets/MediaFinder.php index 3567b2e683..82a1796944 100644 --- a/modules/backend/formwidgets/MediaFinder.php +++ b/modules/backend/formwidgets/MediaFinder.php @@ -1,7 +1,8 @@ formField->disabled) { + $user = BackendAuth::getUser(); + + if ($this->formField->disabled || !$user || !$user->hasAccess('media.manage_media')) { $this->previewMode = true; } } From 45369bccf0029b34690ab74acd9cb8e9dd7f779c Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Tue, 12 Nov 2019 17:02:25 -0600 Subject: [PATCH 102/157] Initial WIP on implementing dependsOn support for filter scopes. Still need to resolve an issue where if the slave filter has values set when the master filter updates, thus triggering a change of the available options to the slave, the original values are still set on the slave but not actually visible in the popup as options because they're no longer valid options. To fix this we'll need the ability to get the browser to refresh the slave filter's selected values (count icon basically since it already forces the options popup to refresh) when its masters update; while at the same rechecking the slave's scope values set on the server to ensure that they're all valid and there aren't values left over from the previous request that are no longer valid but are still being applied to the query. --- modules/backend/classes/FilterScope.php | 54 ++++++------ modules/backend/widgets/Filter.php | 37 ++++++++- .../widgets/filter/partials/_scope_group.htm | 4 +- modules/system/assets/ui/js/filter.js | 82 +++++++++++++++++-- 4 files changed, 144 insertions(+), 33 deletions(-) diff --git a/modules/backend/classes/FilterScope.php b/modules/backend/classes/FilterScope.php index d82cb1f811..bf5d062fb2 100644 --- a/modules/backend/classes/FilterScope.php +++ b/modules/backend/classes/FilterScope.php @@ -51,6 +51,11 @@ class FilterScope */ public $options; + /** + * @var array Other scope names this scope depends on, when the other scopes are modified, this scope will update. + */ + public $dependsOn; + /** * @var string Specifies contextual visibility of this form scope. */ @@ -113,33 +118,32 @@ public function displayAs($type, $config = []) */ protected function evalConfig($config) { - if (isset($config['options'])) { - $this->options = $config['options']; - } - if (isset($config['context'])) { - $this->context = $config['context']; - } - if (isset($config['default'])) { - $this->defaults = $config['default']; - } - if (isset($config['conditions'])) { - $this->conditions = $config['conditions']; + if ($config === null) { + $config = []; } - if (isset($config['scope'])) { - $this->scope = $config['scope']; - } - if (isset($config['cssClass'])) { - $this->cssClass = $config['cssClass']; - } - if (isset($config['nameFrom'])) { - $this->nameFrom = $config['nameFrom']; - } - if (isset($config['descriptionFrom'])) { - $this->descriptionFrom = $config['descriptionFrom']; - } - if (array_key_exists('disabled', $config)) { - $this->disabled = $config['disabled']; + + /* + * Standard config:property values + */ + $applyConfigValues = [ + 'options', + 'dependsOn', + 'context', + 'default', + 'conditions', + 'scope', + 'cssClass', + 'nameFrom', + 'descriptionFrom', + 'disabled', + ]; + + foreach ($applyConfigValues as $value) { + if (array_key_exists($value, $config)) { + $this->{$value} = $config[$value]; + } } + return $config; } diff --git a/modules/backend/widgets/Filter.php b/modules/backend/widgets/Filter.php index 5deb972109..4902b849c6 100644 --- a/modules/backend/widgets/Filter.php +++ b/modules/backend/widgets/Filter.php @@ -171,6 +171,22 @@ public function renderScopeElement($scope) return $this->makePartial('scope_'.$scope->type, $params); } + /** + * Returns a HTML encoded value containing the other scopes this scope depends on + * @param \Backend\Classes\FilterScope $scope + * @return string + */ + protected function getScopeDepends($scope) + { + if (!$scope->dependsOn) { + return ''; + } + + $dependsOn = is_array($scope->dependsOn) ? $scope->dependsOn : [$scope->dependsOn]; + $dependsOn = htmlspecialchars(json_encode($dependsOn), ENT_QUOTES, 'UTF-8'); + return $dependsOn; + } + // // AJAX // @@ -295,7 +311,14 @@ public function onFilterGetOptions() $scope = $this->getScope($scopeName); $activeKeys = $scope->value ? array_keys($scope->value) : []; $available = $this->getAvailableOptions($scope, $searchQuery); - $active = $searchQuery ? [] : $this->filterActiveOptions($activeKeys, $available); + + if ($searchQuery) { + $active = []; + } else { + // Ensure that only valid values are set on the current scope + $active = $this->filterActiveOptions($activeKeys, $available); + $this->setScopeValue($scope, array_keys($active)); + } return [ 'scopeName' => $scopeName, @@ -426,7 +449,11 @@ protected function getOptionsFromArray($scope, $searchQuery = null) ])); } - $options = $model->$methodName(); + if (!empty($scope->dependsOn)) { + $options = $model->$methodName($this->getScopes()); + } else { + $options = $model->$methodName(); + } } elseif (!is_array($options)) { $options = []; @@ -644,6 +671,12 @@ protected function makeFilterScope($name, $config) /* * Set scope value */ + if ($scope->type === 'group') { + + } + + + $scope->value = $this->getScopeValue($scope, @$config['default']); return $scope; diff --git a/modules/backend/widgets/filter/partials/_scope_group.htm b/modules/backend/widgets/filter/partials/_scope_group.htm index e5628d3591..c5cc726eb2 100644 --- a/modules/backend/widgets/filter/partials/_scope_group.htm +++ b/modules/backend/widgets/filter/partials/_scope_group.htm @@ -2,7 +2,9 @@ + data-scope-name="scopeName ?>" + getScopeDepends($scope)): ?>data-scope-depends="" +> label)) ?>: value ? count($scope->value) : e(trans('backend::lang.filter.all')) ?> diff --git a/modules/system/assets/ui/js/filter.js b/modules/system/assets/ui/js/filter.js index b6251fbef8..f3675beed2 100644 --- a/modules/system/assets/ui/js/filter.js +++ b/modules/system/assets/ui/js/filter.js @@ -19,7 +19,6 @@ +function ($) { "use strict"; var FilterWidget = function (element, options) { - this.$el = $(element); this.options = options || {} @@ -28,6 +27,12 @@ this.activeScopeName = null this.isActiveScopeDirty = false + /* + * Throttle dependency updating + */ + this.dependantUpdateInterval = 300 + this.dependantUpdateTimers = {} + this.init() } @@ -89,6 +94,9 @@ FilterWidget.prototype.init = function() { var self = this + this.bindDependants() + + // Setup event handler on type: checkbox scopes this.$el.on('change', '.filter-scope input[type="checkbox"]', function(){ var $scope = $(this).closest('.filter-scope') @@ -100,12 +108,14 @@ } }) + // Apply classes to type: checkbox scopes that are active from the server $('.filter-scope input[type="checkbox"]', this.$el).each(function() { $(this) .closest('.filter-scope') .toggleClass('active', $(this).is(':checked')) }) + // Setup click handler on type: group scopes this.$el.on('click', 'a.filter-scope', function(){ var $scope = $(this), scopeName = $scope.data('scope-name') @@ -120,6 +130,7 @@ $scope.addClass('filter-scope-open') }) + // Setup event handlers on type: group scopes' controls this.$el.on('show.oc.popover', 'a.filter-scope', function(event){ self.focusSearch() @@ -144,9 +155,9 @@ e.preventDefault() self.filterScope(true) }) - }) + // Setup event handler to apply selected options when closing the type: group scope popup this.$el.on('hide.oc.popover', 'a.filter-scope', function(){ var $scope = $(this) self.pushOptions(self.activeScopeName) @@ -158,6 +169,62 @@ }) } + /* + * Bind dependant scopes + */ + FilterWidget.prototype.bindDependants = function() { + if (!$('[data-scope-depends]', this.$el).length) { + return; + } + + var self = this, + scopeMap = {}, + scopeElements = this.$el.find('.filter-scope') + + /* + * Map master and slave scope + */ + scopeElements.filter('[data-scope-depends]').each(function() { + var name = $(this).data('scope-name'), + depends = $(this).data('scope-depends') + + $.each(depends, function(index, depend){ + if (!scopeMap[depend]) { + scopeMap[depend] = { scopes: [] } + } + + scopeMap[depend].scopes.push(name) + }) + }) + + /* + * When a master is updated, refresh its slaves + */ + $.each(scopeMap, function(scopeName, toRefresh){ + scopeElements.filter('[data-scope-name="'+scopeName+'"]') + .on('change.oc.filterScope', $.proxy(self.onRefreshDependants, self, scopeName, toRefresh)) + }) + } + + /* + * Refresh a dependancy scope + * Uses a throttle to prevent duplicate calls and click spamming + */ + FilterWidget.prototype.onRefreshDependants = function(scopeName, toRefresh) { + var self = this, + scopeElements = this.$el.find('.filter-scope') + + if (this.dependantUpdateTimers[scopeName] !== undefined) { + window.clearTimeout(this.dependantUpdateTimers[scopeName]) + } + + this.dependantUpdateTimers[scopeName] = window.setTimeout(function() { + $.each(toRefresh.scopes, function (index, dependantScope) { + self.scopeValues[dependantScope] = null + }) + }, this.dependantUpdateInterval) + } + FilterWidget.prototype.focusSearch = function() { if (Modernizr.touchevents) return @@ -369,7 +436,7 @@ var items = $('#controlFilterPopover .filter-active-items > ul'), buttonContainer = $('#controlFilterPopover .filter-buttons') - if(data) { + if (data) { data.active.length > 0 ? buttonContainer.show() : buttonContainer.hide() } else { items.children().length > 0 ? buttonContainer.show() : buttonContainer.hide() @@ -383,16 +450,21 @@ if (!this.isActiveScopeDirty || !this.options.updateHandler) return - var data = { + var self = this, + data = { scopeName: scopeName, options: this.scopeValues[scopeName] } $.oc.stripeLoadIndicator.show() + this.$el.request(this.options.updateHandler, { data: data - }).always(function(){ + }).always(function () { $.oc.stripeLoadIndicator.hide() + }).done(function () { + // Trigger dependsOn updates on successful requests + self.$el.find('[data-scope-name="'+scopeName+'"]').trigger('change.oc.filterScope') }) } From ee968f25dfa90142a733f6cd6464bc156fc50e50 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Tue, 12 Nov 2019 17:06:23 -0600 Subject: [PATCH 103/157] cleanup --- modules/backend/widgets/Filter.php | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/modules/backend/widgets/Filter.php b/modules/backend/widgets/Filter.php index 4902b849c6..05c9ce786d 100644 --- a/modules/backend/widgets/Filter.php +++ b/modules/backend/widgets/Filter.php @@ -667,16 +667,6 @@ protected function makeFilterScope($name, $config) $scope = new FilterScope($name, $label); $scope->displayAs($scopeType, $config); $scope->idPrefix = $this->alias; - - /* - * Set scope value - */ - if ($scope->type === 'group') { - - } - - - $scope->value = $this->getScopeValue($scope, @$config['default']); return $scope; From 31c93e2c872313ebcec1bc97cae6eb19a0505d97 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Tue, 12 Nov 2019 17:07:10 -0600 Subject: [PATCH 104/157] re-add accidentally removed comment --- modules/backend/widgets/Filter.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/backend/widgets/Filter.php b/modules/backend/widgets/Filter.php index 05c9ce786d..4a6e3e3591 100644 --- a/modules/backend/widgets/Filter.php +++ b/modules/backend/widgets/Filter.php @@ -667,6 +667,10 @@ protected function makeFilterScope($name, $config) $scope = new FilterScope($name, $label); $scope->displayAs($scopeType, $config); $scope->idPrefix = $this->alias; + + /* + * Set scope value + */ $scope->value = $this->getScopeValue($scope, @$config['default']); return $scope; From 6365dc1993941e559495a0e5f5a9cdb513fef844 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Wed, 13 Nov 2019 13:55:06 -0600 Subject: [PATCH 105/157] Implemented client side refresh of dependent options & server side checking of valid filter values before applying them to the query --- modules/backend/widgets/Filter.php | 15 ++++++++++++++- modules/system/assets/ui/js/filter.js | 19 +++++++++++++++++++ modules/system/assets/ui/less/filter.less | 21 +++++++++++++++++++++ modules/system/assets/ui/storm-min.js | 23 ++++++++++++++++++++--- modules/system/assets/ui/storm.css | 3 +++ 5 files changed, 77 insertions(+), 4 deletions(-) diff --git a/modules/backend/widgets/Filter.php b/modules/backend/widgets/Filter.php index 4a6e3e3591..738b812320 100644 --- a/modules/backend/widgets/Filter.php +++ b/modules/backend/widgets/Filter.php @@ -317,7 +317,7 @@ public function onFilterGetOptions() } else { // Ensure that only valid values are set on the current scope $active = $this->filterActiveOptions($activeKeys, $available); - $this->setScopeValue($scope, array_keys($active)); + $this->setScopeValue($scope, $active); } return [ @@ -690,6 +690,15 @@ public function applyAllScopesToQuery($query) $this->defineFilterScopes(); foreach ($this->allScopes as $scope) { + // Ensure that only valid values are set scopes of type: group + if ($scope->type === 'group') { + $activeKeys = $scope->value ? array_keys($scope->value) : []; + $available = $this->getAvailableOptions($scope); + $active = $this->filterActiveOptions($activeKeys, $available); + $value = !empty($active) ? $active : null; + $this->setScopeValue($scope, $value); + } + $this->applyScopeToQuery($scope, $query); } @@ -832,6 +841,10 @@ public function applyScopeToQuery($scope, $query) default: $value = is_array($scope->value) ? array_keys($scope->value) : $scope->value; + if (empty($value)) { + break; + } + /* * Condition */ diff --git a/modules/system/assets/ui/js/filter.js b/modules/system/assets/ui/js/filter.js index f3675beed2..543575e9ab 100644 --- a/modules/system/assets/ui/js/filter.js +++ b/modules/system/assets/ui/js/filter.js @@ -221,8 +221,27 @@ this.dependantUpdateTimers[scopeName] = window.setTimeout(function() { $.each(toRefresh.scopes, function (index, dependantScope) { self.scopeValues[dependantScope] = null + var $scope = self.$el.find('[data-scope-name="'+dependantScope+'"]') + + /* + * Request options from server + */ + self.$el.request(self.options.optionsHandler, { + data: { scopeName: dependantScope }, + success: function(data) { + self.fillOptions(dependantScope, data.options) + self.updateScopeSetting($scope, data.options.active.length) + $scope.loadIndicator('hide') + } + }) }) }, this.dependantUpdateInterval) + + $.each(toRefresh.scopes, function(index, scope) { + scopeElements.filter('[data-scope-name="'+scope+'"]') + .addClass('loading-indicator-container') + .loadIndicator() + }) } FilterWidget.prototype.focusSearch = function() { diff --git a/modules/system/assets/ui/less/filter.less b/modules/system/assets/ui/less/filter.less index 071ed06585..3d591af835 100644 --- a/modules/system/assets/ui/less/filter.less +++ b/modules/system/assets/ui/less/filter.less @@ -55,6 +55,27 @@ .transition(color 0.6s); } + &.loading-indicator-container.in-progress { + pointer-events: none; + cursor: default; + + .loading-indicator { + background: transparent; + + > span { + left: unset; + right: 0; + top: 10px; + background-color: @color-filter-bg; + border-radius: 50%; + margin-top: 0; + width: 20px; + height: 20px; + background-size: 15px 15px; + } + } + } + &:after { font-size: 14px; .icon(@angle-down); diff --git a/modules/system/assets/ui/storm-min.js b/modules/system/assets/ui/storm-min.js index d556981b3e..f3fe8efe3c 100644 --- a/modules/system/assets/ui/storm-min.js +++ b/modules/system/assets/ui/storm-min.js @@ -3046,6 +3046,8 @@ this.scopeValues={} this.$activeScope=null this.activeScopeName=null this.isActiveScopeDirty=false +this.dependantUpdateInterval=300 +this.dependantUpdateTimers={} this.init()} FilterWidget.DEFAULTS={optionsHandler:null,updateHandler:null} FilterWidget.prototype.getPopoverTemplate=function(){return' \ @@ -3093,6 +3095,7 @@ FilterWidget.prototype.getPopoverTemplate=function(){return' \ '} FilterWidget.prototype.init=function(){var self=this +this.bindDependants() this.$el.on('change','.filter-scope input[type="checkbox"]',function(){var $scope=$(this).closest('.filter-scope') if($scope.hasClass('is-indeterminate')){self.switchToggle($(this))} else{self.checkboxToggle($(this))}}) @@ -3117,6 +3120,20 @@ self.pushOptions(self.activeScopeName) self.activeScopeName=null self.$activeScope=null setTimeout(function(){$scope.removeClass('filter-scope-open')},200)})} +FilterWidget.prototype.bindDependants=function(){if(!$('[data-scope-depends]',this.$el).length){return;} +var self=this,scopeMap={},scopeElements=this.$el.find('.filter-scope') +scopeElements.filter('[data-scope-depends]').each(function(){var name=$(this).data('scope-name'),depends=$(this).data('scope-depends') +$.each(depends,function(index,depend){if(!scopeMap[depend]){scopeMap[depend]={scopes:[]}} +scopeMap[depend].scopes.push(name)})}) +$.each(scopeMap,function(scopeName,toRefresh){scopeElements.filter('[data-scope-name="'+scopeName+'"]').on('change.oc.filterScope',$.proxy(self.onRefreshDependants,self,scopeName,toRefresh))})} +FilterWidget.prototype.onRefreshDependants=function(scopeName,toRefresh){var self=this,scopeElements=this.$el.find('.filter-scope') +if(this.dependantUpdateTimers[scopeName]!==undefined){window.clearTimeout(this.dependantUpdateTimers[scopeName])} +this.dependantUpdateTimers[scopeName]=window.setTimeout(function(){$.each(toRefresh.scopes,function(index,dependantScope){self.scopeValues[dependantScope]=null +var $scope=self.$el.find('[data-scope-name="'+dependantScope+'"]') +self.$el.request(self.options.optionsHandler,{data:{scopeName:dependantScope},success:function(data){self.fillOptions(dependantScope,data.options) +self.updateScopeSetting($scope,data.options.active.length) +$scope.loadIndicator('hide')}})})},this.dependantUpdateInterval) +$.each(toRefresh.scopes,function(index,scope){scopeElements.filter('[data-scope-name="'+scope+'"]').addClass('loading-indicator-container').loadIndicator()})} FilterWidget.prototype.focusSearch=function(){if(Modernizr.touchevents) return var $input=$('#controlFilterPopover input.filter-search-input'),length=$input.val().length @@ -3191,9 +3208,9 @@ FilterWidget.prototype.toggleFilterButtons=function(data) if(data){data.active.length>0?buttonContainer.show():buttonContainer.hide()}else{items.children().length>0?buttonContainer.show():buttonContainer.hide()}} FilterWidget.prototype.pushOptions=function(scopeName){if(!this.isActiveScopeDirty||!this.options.updateHandler) return -var data={scopeName:scopeName,options:this.scopeValues[scopeName]} +var self=this,data={scopeName:scopeName,options:this.scopeValues[scopeName]} $.oc.stripeLoadIndicator.show() -this.$el.request(this.options.updateHandler,{data:data}).always(function(){$.oc.stripeLoadIndicator.hide()})} +this.$el.request(this.options.updateHandler,{data:data}).always(function(){$.oc.stripeLoadIndicator.hide()}).done(function(){self.$el.find('[data-scope-name="'+scopeName+'"]').trigger('change.oc.filterScope')})} FilterWidget.prototype.checkboxToggle=function($el){var isChecked=$el.is(':checked'),$scope=$el.closest('.filter-scope'),scopeName=$scope.data('scope-name') this.scopeValues[scopeName]=isChecked if(this.options.updateHandler){var data={scopeName:scopeName,value:isChecked} @@ -3902,7 +3919,7 @@ $.oc.chartUtils=new ChartUtils();}(window.jQuery);+function($){"use strict";var this.chartOptions={xaxis:{mode:"time",tickLength:5},selection:{mode:"x"},grid:{markingsColor:"rgba(0,0,0, 0.02)",backgroundColor:{colors:["#fff","#fff"]},borderColor:"#7bafcc",borderWidth:0,color:"#ddd",hoverable:true,clickable:true,labelMargin:10},series:{lines:{show:true,fill:true},points:{show:true}},tooltip:true,tooltipOpts:{defaultTheme:false,content:"%x: %y",dateFormat:"%y-%0m-%0d",shifts:{x:10,y:20}},legend:{show:true,noColumns:2}} this.defaultDataSetOptions={shadowSize:0} var parsedOptions={} -try{parsedOptions=ocJSON("{"+value+"}");}catch(e){throw new Error('Error parsing the data-chart-options attribute value. '+e);} +try{parsedOptions=ocJSON("{"+options.chartOptions+"}");}catch(e){throw new Error('Error parsing the data-chart-options attribute value. '+e);} this.chartOptions=$.extend({},this.chartOptions,parsedOptions) this.options=options this.$el=$(element) diff --git a/modules/system/assets/ui/storm.css b/modules/system/assets/ui/storm.css index e37b2c0535..78c3097844 100644 --- a/modules/system/assets/ui/storm.css +++ b/modules/system/assets/ui/storm.css @@ -4786,6 +4786,9 @@ ul.autocomplete.dropdown-menu.inspector-autocomplete li a {padding:5px 12px;whit .control-filter >.filter-scope {display:inline-block;padding:10px} .control-filter >.filter-scope .filter-label {margin-right:5px} .control-filter >.filter-scope .filter-setting {display:inline-block;margin-right:5px;-webkit-transition:color 0.6s;transition:color 0.6s} +.control-filter >.filter-scope.loading-indicator-container.in-progress {pointer-events:none;cursor:default} +.control-filter >.filter-scope.loading-indicator-container.in-progress .loading-indicator {background:transparent} +.control-filter >.filter-scope.loading-indicator-container.in-progress .loading-indicator >span {left:unset;right:0;top:10px;background-color:#ecf0f1;border-radius:50%;margin-top:0;width:20px;height:20px;background-size:15px 15px} .control-filter >.filter-scope:after {font-size:14px;font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;content:"\f107"} .control-filter >.filter-scope.active .filter-setting {padding-left:5px;padding-right:5px;color:#FFF;background-color:#6aab55;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-transition:color 1s,background-color 1s;transition:color 1s,background-color 1s} .control-filter >.filter-scope.checkbox {padding-left:35px} From 1cc4ca87943712c278a18274df799c07e4d0dee9 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Fri, 15 Nov 2019 15:40:57 -0600 Subject: [PATCH 106/157] Minor cleanup from #4764 --- modules/backend/widgets/Filter.php | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/modules/backend/widgets/Filter.php b/modules/backend/widgets/Filter.php index 738b812320..ddb8b68925 100644 --- a/modules/backend/widgets/Filter.php +++ b/modules/backend/widgets/Filter.php @@ -311,14 +311,7 @@ public function onFilterGetOptions() $scope = $this->getScope($scopeName); $activeKeys = $scope->value ? array_keys($scope->value) : []; $available = $this->getAvailableOptions($scope, $searchQuery); - - if ($searchQuery) { - $active = []; - } else { - // Ensure that only valid values are set on the current scope - $active = $this->filterActiveOptions($activeKeys, $available); - $this->setScopeValue($scope, $active); - } + $active = $searchQuery ? [] : $this->filterActiveOptions($activeKeys, $available); return [ 'scopeName' => $scopeName, From e67df65821203e187c090284325c0ad33bd3c141 Mon Sep 17 00:00:00 2001 From: Ben Thomson Date: Sat, 16 Nov 2019 16:27:37 +0800 Subject: [PATCH 107/157] Fix copy and paste on alert popups (#4740) --- modules/backend/assets/js/october-min.js | 2 +- modules/backend/assets/vendor/sweet-alert/sweet-alert.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/backend/assets/js/october-min.js b/modules/backend/assets/js/october-min.js index e053435ccc..a25834ef2e 100644 --- a/modules/backend/assets/js/october-min.js +++ b/modules/backend/assets/js/october-min.js @@ -240,7 +240,7 @@ elem.className=newClass.replace(/^\s+|\s+$/g,'');}},escapeHtml=function(str){var for(var i=0;i0){setTimeout(tick,interval);}else{elem.style.display='none';}};tick();},fireClick=function(node){if(MouseEvent){var mevt=new MouseEvent('click',{view:window,bubbles:false,cancelable:true});node.dispatchEvent(mevt);}else if(document.createEvent){var evt=document.createEvent('MouseEvents');evt.initEvent('click',false,false);node.dispatchEvent(evt);}else if(document.createEventObject){node.fireEvent('onclick');}else if(typeof node.onclick==='function'){node.onclick();}},stopEventPropagation=function(e){if(typeof e.stopPropagation==='function'){e.stopPropagation();e.preventDefault();}else if(window.event&&window.event.hasOwnProperty('cancelBubble')){window.event.cancelBubble=true;}};var previousActiveElement,previousDocumentClick,previousWindowKeyDown,lastFocusedButton;window.sweetAlertInitialize=function(){var sweetHTML='

Title

Text

',sweetWrap=document.createElement('div');sweetWrap.innerHTML=sweetHTML;document.body.appendChild(sweetWrap);} +return false;},getTopMargin=function(elem){elem.style.left='-9999px';elem.style.display='block';var height=elem.clientHeight;var padding=parseInt(getComputedStyle(elem).getPropertyValue('padding'),10);elem.style.left='';elem.style.display='none';return('-'+parseInt(height/2+padding)+'px');},fadeIn=function(elem,interval){if(+elem.style.opacity<1){interval=interval||16;elem.style.opacity=0;elem.style.display='block';var last=+new Date();var tick=function(){elem.style.opacity=+elem.style.opacity+(new Date()-last)/100;last=+new Date();if(+elem.style.opacity<1){setTimeout(tick,interval);}};tick();}},fadeOut=function(elem,interval){interval=interval||16;elem.style.opacity=1;var last=+new Date();var tick=function(){elem.style.opacity=+elem.style.opacity-(new Date()-last)/100;last=+new Date();if(+elem.style.opacity>0){setTimeout(tick,interval);}else{elem.style.display='none';}};tick();},fireClick=function(node){if(MouseEvent){var mevt=new MouseEvent('click',{view:window,bubbles:false,cancelable:true});node.dispatchEvent(mevt);}else if(document.createEvent){var evt=document.createEvent('MouseEvents');evt.initEvent('click',false,false);node.dispatchEvent(evt);}else if(document.createEventObject){node.fireEvent('onclick');}else if(typeof node.onclick==='function'){node.onclick();}},stopEventPropagation=function(e){if(typeof e.stopPropagation==='function'){e.stopPropagation();e.preventDefault();}else if(window.event&&window.event.hasOwnProperty('cancelBubble')){window.event.cancelBubble=true;}};var previousActiveElement,previousDocumentClick,previousWindowKeyDown,lastFocusedButton;window.sweetAlertInitialize=function(){var sweetHTML='

Title

Text

',sweetWrap=document.createElement('div');sweetWrap.innerHTML=sweetHTML;document.body.appendChild(sweetWrap);} window.sweetAlert=window.swal=function(){if(arguments[0]===undefined){window.console.error('sweetAlert expects at least 1 attribute!');return false;} var params=extend({},defaultParams);switch(typeof arguments[0]){case'string':params.title=arguments[0];params.text=arguments[1]||'';params.type=arguments[2]||'';break;case'object':if(arguments[0].title===undefined){window.console.error('Missing "title" argument!');return false;} params.title=arguments[0].title;params.text=arguments[0].text||defaultParams.text;params.type=arguments[0].type||defaultParams.type;params.allowOutsideClick=arguments[0].allowOutsideClick||defaultParams.allowOutsideClick;params.showCancelButton=arguments[0].showCancelButton!==undefined?arguments[0].showCancelButton:defaultParams.showCancelButton;params.showConfirmButton=arguments[0].showConfirmButton!==undefined?arguments[0].showConfirmButton:defaultParams.showConfirmButton;params.closeOnConfirm=arguments[0].closeOnConfirm!==undefined?arguments[0].closeOnConfirm:defaultParams.closeOnConfirm;params.closeOnCancel=arguments[0].closeOnCancel!==undefined?arguments[0].closeOnCancel:defaultParams.closeOnCancel;params.timer=arguments[0].timer||defaultParams.timer;params.confirmButtonText=(defaultParams.showCancelButton)?'Confirm':defaultParams.confirmButtonText;params.confirmButtonText=arguments[0].confirmButtonText||defaultParams.confirmButtonText;params.confirmButtonClass=arguments[0].confirmButtonClass||(arguments[0].type?'btn-'+arguments[0].type:null)||defaultParams.confirmButtonClass;params.cancelButtonText=arguments[0].cancelButtonText||defaultParams.cancelButtonText;params.cancelButtonClass=arguments[0].cancelButtonClass||defaultParams.cancelButtonClass;params.containerClass=arguments[0].containerClass||defaultParams.containerClass;params.titleClass=arguments[0].titleClass||defaultParams.titleClass;params.textClass=arguments[0].textClass||defaultParams.textClass;params.imageUrl=arguments[0].imageUrl||defaultParams.imageUrl;params.imageSize=arguments[0].imageSize||defaultParams.imageSize;params.doneFunction=arguments[1]||null;break;default:window.console.error('Unexpected type of argument! Expected "string" or "object", got '+typeof arguments[0]);return false;} diff --git a/modules/backend/assets/vendor/sweet-alert/sweet-alert.js b/modules/backend/assets/vendor/sweet-alert/sweet-alert.js index 77505356c2..65c1d6f562 100644 --- a/modules/backend/assets/vendor/sweet-alert/sweet-alert.js +++ b/modules/backend/assets/vendor/sweet-alert/sweet-alert.js @@ -181,7 +181,7 @@ */ window.sweetAlertInitialize = function() { - var sweetHTML = '

Title

Text

', + var sweetHTML = '

Title

Text

', sweetWrap = document.createElement('div'); sweetWrap.innerHTML = sweetHTML; @@ -558,7 +558,7 @@ } else { hide($cancelBtn); } - + // Confirm button modal.setAttribute('data-has-confirm-button', params.showConfirmButton); if (params.showConfirmButton) { @@ -566,7 +566,7 @@ } else { hide($confirmBtn); } - + // Edit text on cancel and confirm buttons if (params.cancelButtonText) { From d7f32622e83ddfc55326b941cda4c7dadc3a1903 Mon Sep 17 00:00:00 2001 From: Marek Erben Date: Tue, 19 Nov 2019 04:49:05 +0100 Subject: [PATCH 108/157] Improved Czech translations in /modules/system/lang (#4773) Credit to @maraerben. --- modules/system/lang/cs/client.php | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/modules/system/lang/cs/client.php b/modules/system/lang/cs/client.php index 9d58ca19f2..4995e1d09f 100644 --- a/modules/system/lang/cs/client.php +++ b/modules/system/lang/cs/client.php @@ -33,7 +33,6 @@ 'fullscreen' => 'Celá obrazovka', 'preview' => 'Náhled', ], - 'mediamanager' => [ 'insert_link' => "Vložit odkaz", 'insert_image' => "Vložit obrázek", @@ -45,25 +44,28 @@ 'invalid_video_empty_insert' => "Vyberte video soubor pro vložení.", 'invalid_audio_empty_insert' => "Vyberte audio soubor pro vložení.", ], - 'alert' => [ 'confirm_button_text' => 'OK', 'cancel_button_text' => 'Zrušit', - 'widget_remove_confirm' => 'Odstranit widget?' + 'widget_remove_confirm' => 'Odstranit widget?', ], 'datepicker' => [ 'previousMonth' => 'Předchozí měsíc', 'nextMonth' => 'Následující měsíc', 'months' => ['Leden', 'Únor', 'Březen', 'Duben', 'Květen', 'Červen', 'Červenec', 'Srpen', 'Září', 'Říjen', 'Listopad', 'Prosinec'], 'weekdays' => ['Neděle', 'Pondělí', 'Úterý', 'Středa', 'Čtvrtek', 'Pátek', 'Sobota'], - 'weekdaysShort' => ['Ne', 'Po', 'Út', 'St', 'Čt', 'Pá', 'So'] + 'weekdaysShort' => ['Ne', 'Po', 'Út', 'St', 'Čt', 'Pá', 'So'], ], 'colorpicker' => [ 'choose' => 'Ok', ], 'filter' => [ 'group' => [ - 'all' => 'Vše' + 'all' => 'Vše', + ], + 'scopes' => [ + 'apply_button_text' => 'Filtrovat', + 'clear_button_text' => 'Zrušit', ], 'dates' => [ 'all' => 'Vše', @@ -71,8 +73,15 @@ 'reset_button_text' => 'Zrušit', 'date_placeholder' => 'Datum', 'after_placeholder' => 'Po', - 'before_placeholder' => 'Před' - ] + 'before_placeholder' => 'Před', + ], + 'numbers' => [ + 'all' => 'Vše', + 'filter_button_text' => 'Filtrovat', + 'reset_button_text' => 'Zrušit', + 'min_placeholder' => 'Minimum', + 'max_placeholder' => 'Maximum', + ], ], 'eventlog' => [ 'show_stacktrace' => 'Zobrazit stacktrace', @@ -87,7 +96,7 @@ 'openWith' => 'Otevřít v', 'remember_choice' => 'Zapamatovat si vybranou volbu pro tuto relaci', 'open' => 'Otevřít', - 'cancel' => 'Zrušit' - ] - ] + 'cancel' => 'Zrušit', + ], + ], ]; From 7d7f462246ec3a0f38d1edc5ec28e58736dc48f1 Mon Sep 17 00:00:00 2001 From: Jim Cottrell Date: Tue, 19 Nov 2019 00:13:08 -0700 Subject: [PATCH 109/157] Restore support for Select2 data format in custom select control (#4712) Credit to @jimcottrell. Refs: #4413 --- modules/system/assets/ui/docs/select.md | 62 +++++++++++-- modules/system/assets/ui/js/select.js | 37 ++++---- modules/system/assets/ui/storm-min.js | 7 +- tests/js/cases/system/ui.select.test.js | 111 ++++++++++++++++++++++++ 4 files changed, 190 insertions(+), 27 deletions(-) create mode 100644 tests/js/cases/system/ui.select.test.js diff --git a/modules/system/assets/ui/docs/select.md b/modules/system/assets/ui/docs/select.md index 2b13f08d7e..8716983896 100644 --- a/modules/system/assets/ui/docs/select.md +++ b/modules/system/assets/ui/docs/select.md @@ -71,24 +71,68 @@ Use the `data-handler` attribute to source the select options from an AJAX handl > ``` -The AJAX handler should return results as an array. +The AJAX handler should return results in the [Select2 data format](https://select2.org/data-sources/formats). ```php public function onGetOptions() { - $results = [ - [ - 'id' => 1, - 'text' => 'Foobar', - ], - ... + return [ + 'results' => [ + [ + 'id' => 1, + 'text' => 'Foo' + ], + [ + 'id' => 2, + 'text' => 'Bar' + ] + ... + ] ]; +} +``` - return ['result' => $results]; +Or a more full-featured example: + +```php +public function onGetOptions() +{ + return [ + 'results' => [ + [ + 'id' => 1, + 'text' => 'Foo', + 'disabled' => true + ], + [ + 'id' => 2, + 'text' => 'Bar', + 'selected' => true + ], + [ + 'text' => 'Group', + 'children' => [ + [ + 'id' => 3, + 'text' => 'Child 1' + ], + [ + 'id' => 4, + 'text' => 'Child 2' + ] + ... + ] + ] + ... + ], + 'pagination' => [ + 'more' => true + ] + ]; } ``` -Due to the fact that JavaScript reorders numeric keys when interpreting the JSON data received by the AJAX handler, we suggest the method above for defining `results`. Support for the original `results` array format is however retained to ensure backwards compatibility. +The results array can be assigned to either the `result` or `results` key. As an alternative to the Select2 format, results can also be provided as an associative array (also assigned to either key). Due to the fact that JavaScript does not guarantee the order of object properties, we suggest the method above for defining results. ```php public function onGetOptions() diff --git a/modules/system/assets/ui/js/select.js b/modules/system/assets/ui/js/select.js index 86a3afe869..a7c6c5190a 100644 --- a/modules/system/assets/ui/js/select.js +++ b/modules/system/assets/ui/js/select.js @@ -87,23 +87,26 @@ return $request }, processResults: function (data, params) { - var results = data.result; - var options = []; - - for (var i in results) { - if (results.hasOwnProperty(i)) { - var isObject = i != null && i.constructor.name === 'Object'; - - options.push({ - id: isObject ? results[i].id : i, - text: isObject ? results[i].text : results[i], - }); - }; - }; - - return { - results: options, - }; + var results = data.result || data.results, + options = [] + + delete(data.result) + if (results[0] && typeof(results[0]) === 'object') { // Pass through Select2 format + options = results + } + else { // Key-value map + for (var i in results) { + if (results.hasOwnProperty(i)) { + options.push({ + id: i, + text: results[i], + }) + } + } + } + + data.results = options + return data }, dataType: 'json' } diff --git a/modules/system/assets/ui/storm-min.js b/modules/system/assets/ui/storm-min.js index f3fe8efe3c..23f2c4ebe6 100644 --- a/modules/system/assets/ui/storm-min.js +++ b/modules/system/assets/ui/storm-min.js @@ -3514,7 +3514,12 @@ if($element.hasClass('select-hide-selected')){extraOptions.dropdownCssClass+=' s var source=$element.data('handler');if(source){extraOptions.ajax={transport:function(params,success,failure){var $request=$element.request(source,{data:params.data}) $request.done(success) $request.fail(failure) -return $request},processResults:function(data,params){var results=data.result;var options=[];for(var i in results){if(results.hasOwnProperty(i)){var isObject=i!=null&&i.constructor.name==='Object';options.push({id:isObject?results[i].id:i,text:isObject?results[i].text:results[i],});};};return{results:options,};},dataType:'json'}} +return $request},processResults:function(data,params){var results=data.result||data.results,options=[] +delete(data.result) +if(results[0]&&typeof(results[0])==='object'){options=results} +else{for(var i in results){if(results.hasOwnProperty(i)){options.push({id:i,text:results[i],})}}} +data.results=options +return data},dataType:'json'}} var separators=$element.data('token-separators') if(separators){extraOptions.tags=true extraOptions.tokenSeparators=separators.split('|') diff --git a/tests/js/cases/system/ui.select.test.js b/tests/js/cases/system/ui.select.test.js new file mode 100644 index 0000000000..17f854789e --- /dev/null +++ b/tests/js/cases/system/ui.select.test.js @@ -0,0 +1,111 @@ +import { assert } from 'chai' +import fakeDom from 'helpers/fakeDom' + +describe('modules/system/assets/ui/js/select.js', function () { + describe('AJAX processResults function', function () { + let dom, + window, + processResults, + keyValResultFormat = { + value1: 'text1', + value2: 'text2' + }, + select2ResultFormat = [ + { + id: 'value1', + text: 'text1', + disabled: true + }, + { + id: 'value2', + text: 'text2', + selected: false + } + ] + + this.timeout(1000) + + beforeEach((done) => { + // Load framework.js and select.js in the fake DOM + dom = fakeDom(` + + + + + `) + + window = dom.window + + window.selectScript.onload = () => { + window.jQuery.fn.select2 = function(options) { + processResults = options.ajax.processResults + done() + } + } + }) + + afterEach(() => { + window.close() + }) + + it('supports a key-value mapping on the "result" key', function () { + let result = processResults({ result: keyValResultFormat }) + assert.deepEqual(result, { results: [ + { + id: 'value1', + text: 'text1' + }, + { + id: 'value2', + text: 'text2' + } + ]}) + }) + + it('supports a key-value mapping on the "results" key', function() { + let result = processResults({ results: keyValResultFormat }) + assert.deepEqual(result, { results: [ + { + id: 'value1', + text: 'text1' + }, + { + id: 'value2', + text: 'text2' + } + ]}) + }) + + it('passes through other data provided with key-value mapping', function() { + let result = processResults({ result: keyValResultFormat, other1: 1, other2: '2' }) + assert.include(result, { other1: 1, other2: '2'}) + }) + + it('supports the Select2 result format on the "result" key', function() { + let result = processResults({ result: select2ResultFormat }) + assert.deepEqual(result, { results: select2ResultFormat }) + }) + + it('passes through the Select2 result format on the "results" key', function() { + let result = processResults({ results: select2ResultFormat }) + assert.deepEqual(result, { results: select2ResultFormat }) + }) + + it('passes through other data provided with Select2 results format', function() { + let result = processResults({ results: select2ResultFormat, pagination: { more: true }, other: 'value' }) + assert.deepInclude(result, { pagination: { more: true }, other: 'value' }) + }) + + it('passes through the Select2 format with a group as the first entry', function() { + let data = [ + { + text: 'Label', + children: select2ResultFormat + } + ] + + let result = processResults({ results: data }) + assert.deepEqual(result, { results: data }) + }) + }) +}) From e2ab8cf8b293a57da98eb07a34ef870009db327c Mon Sep 17 00:00:00 2001 From: Samuell Date: Wed, 20 Nov 2019 18:09:33 +0100 Subject: [PATCH 110/157] Improved Slovak translation (#4778) Credit to @Samuell1 --- modules/backend/lang/sk/lang.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/backend/lang/sk/lang.php b/modules/backend/lang/sk/lang.php index 58812061a5..3741cea890 100644 --- a/modules/backend/lang/sk/lang.php +++ b/modules/backend/lang/sk/lang.php @@ -294,7 +294,7 @@ 'cancel' => 'Zrušiť', 'close' => 'Zatvoriť', 'add_name' => 'Pridať :name', - 'create' => 'Vytvorť', + 'create' => 'Vytvoriť', 'create_name' => 'Vytvoriť :name', 'update' => 'Upraviť', 'update_name' => 'Upraviť :name', From 3b0ec28f43868290ab9915eff48b7f716acb62f6 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Fri, 22 Nov 2019 18:39:25 -0600 Subject: [PATCH 111/157] Fixed conflict between JS input trigger plugin & JS filter plugin. Related: https://github.com/octobercms/october/issues/3202#issuecomment-556042766 --- modules/system/assets/ui/js/filter.dates.js | 12 +++---- modules/system/assets/ui/js/filter.js | 8 ++--- modules/system/assets/ui/js/filter.numbers.js | 12 +++---- modules/system/assets/ui/storm-min.js | 32 +++++++++---------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/modules/system/assets/ui/js/filter.dates.js b/modules/system/assets/ui/js/filter.dates.js index e6d12aa07a..2d5750746f 100644 --- a/modules/system/assets/ui/js/filter.dates.js +++ b/modules/system/assets/ui/js/filter.dates.js @@ -43,14 +43,14 @@ this.$el.on('show.oc.popover', 'a.filter-scope-date', function (event) { self.initDatePickers($(this).hasClass('range')) - $(event.relatedTarget).on('click', '#controlFilterPopoverDate [data-trigger="filter"]', function (e) { + $(event.relatedTarget).on('click', '#controlFilterPopoverDate [data-filter-action="filter"]', function (e) { e.preventDefault() e.stopPropagation() self.filterByDate() }) - $(event.relatedTarget).on('click', '#controlFilterPopoverDate [data-trigger="clear"]', function (e) { + $(event.relatedTarget).on('click', '#controlFilterPopoverDate [data-filter-action="clear"]', function (e) { e.preventDefault() e.stopPropagation() @@ -121,7 +121,7 @@ \ \
\ - \
\ @@ -159,16 +159,16 @@ type="text" \ name="date" \ value="{{ date }}" \ - class="form-control align-right popup-allow-focus" \ + class="form-control align-right popup-allow-focus" \ autocomplete="off" \ placeholder="{{ before_placeholder }}" /> \ \ \
\ - \ - \
\ diff --git a/modules/system/assets/ui/js/filter.js b/modules/system/assets/ui/js/filter.js index 543575e9ab..fa71d983c2 100644 --- a/modules/system/assets/ui/js/filter.js +++ b/modules/system/assets/ui/js/filter.js @@ -78,10 +78,10 @@ \ \
\ - \ - \
\ @@ -146,12 +146,12 @@ self.filterAvailable(data.scopeName, data.options.available) }) - $(event.relatedTarget).on('click', '#controlFilterPopover [data-trigger="apply"]', function (e) { + $(event.relatedTarget).on('click', '#controlFilterPopover [data-filter-action="apply"]', function (e) { e.preventDefault() self.filterScope() }) - $(event.relatedTarget).on('click', '#controlFilterPopover [data-trigger="clear"]', function (e) { + $(event.relatedTarget).on('click', '#controlFilterPopover [data-filter-action="clear"]', function (e) { e.preventDefault() self.filterScope(true) }) diff --git a/modules/system/assets/ui/js/filter.numbers.js b/modules/system/assets/ui/js/filter.numbers.js index a57484c19a..1a2cb071f3 100644 --- a/modules/system/assets/ui/js/filter.numbers.js +++ b/modules/system/assets/ui/js/filter.numbers.js @@ -42,13 +42,13 @@ this.$el.on('show.oc.popover', 'a.filter-scope-number', function (event) { self.initNumberInputs($(this).hasClass('range')) - $(event.relatedTarget).on('click', '#controlFilterPopoverNum [data-trigger="filter"]', function (e) { + $(event.relatedTarget).on('click', '#controlFilterPopoverNum [data-filter-action="filter"]', function (e) { e.preventDefault() e.stopPropagation() self.filterByNumber() }) - $(event.relatedTarget).on('click', '#controlFilterPopoverNum [data-trigger="clear"]', function (e) { + $(event.relatedTarget).on('click', '#controlFilterPopoverNum [data-filter-action="clear"]', function (e) { e.preventDefault() e.stopPropagation() @@ -111,10 +111,10 @@ placeholder="{{ number_placeholder }}" /> \ \
\ - \ - \
\ @@ -157,10 +157,10 @@ \ \
\ - \ - \
\ diff --git a/modules/system/assets/ui/storm-min.js b/modules/system/assets/ui/storm-min.js index 23f2c4ebe6..a3881f4283 100644 --- a/modules/system/assets/ui/storm-min.js +++ b/modules/system/assets/ui/storm-min.js @@ -3083,10 +3083,10 @@ FilterWidget.prototype.getPopoverTemplate=function(){return' \ \
\ - \ - \
\ @@ -3111,9 +3111,9 @@ this.$el.on('show.oc.popover','a.filter-scope',function(event){self.focusSearch( $(event.relatedTarget).on('click','#controlFilterPopover .filter-items > ul > li',function(){self.selectItem($(this))}) $(event.relatedTarget).on('click','#controlFilterPopover .filter-active-items > ul > li',function(){self.selectItem($(this),true)}) $(event.relatedTarget).on('ajaxDone','#controlFilterPopover input.filter-search-input',function(event,context,data){self.filterAvailable(data.scopeName,data.options.available)}) -$(event.relatedTarget).on('click','#controlFilterPopover [data-trigger="apply"]',function(e){e.preventDefault() +$(event.relatedTarget).on('click','#controlFilterPopover [data-filter-action="apply"]',function(e){e.preventDefault() self.filterScope()}) -$(event.relatedTarget).on('click','#controlFilterPopover [data-trigger="clear"]',function(e){e.preventDefault() +$(event.relatedTarget).on('click','#controlFilterPopover [data-filter-action="clear"]',function(e){e.preventDefault() self.filterScope(true)})}) this.$el.on('hide.oc.popover','a.filter-scope',function(){var $scope=$(this) self.pushOptions(self.activeScopeName) @@ -3246,10 +3246,10 @@ this.initRegion() this.initFilterDate()} FilterWidget.prototype.initFilterDate=function(){var self=this this.$el.on('show.oc.popover','a.filter-scope-date',function(event){self.initDatePickers($(this).hasClass('range')) -$(event.relatedTarget).on('click','#controlFilterPopoverDate [data-trigger="filter"]',function(e){e.preventDefault() +$(event.relatedTarget).on('click','#controlFilterPopoverDate [data-filter-action="filter"]',function(e){e.preventDefault() e.stopPropagation() self.filterByDate()}) -$(event.relatedTarget).on('click','#controlFilterPopoverDate [data-trigger="clear"]',function(e){e.preventDefault() +$(event.relatedTarget).on('click','#controlFilterPopoverDate [data-filter-action="clear"]',function(e){e.preventDefault() e.stopPropagation() self.filterByDate(true)})}) this.$el.on('hiding.oc.popover','a.filter-scope-date',function(){self.clearDatePickers()}) @@ -3285,7 +3285,7 @@ FilterWidget.prototype.getPopoverDateTemplate=function(){return' \ \
\ - \
\ @@ -3317,16 +3317,16 @@ FilterWidget.prototype.getPopoverRangeTemplate=function(){return' type="text" \ name="date" \ value="{{ date }}" \ - class="form-control align-right popup-allow-focus" \ + class="form-control align-right popup-allow-focus" \ autocomplete="off" \ placeholder="{{ before_placeholder }}" /> \ \ \
\ - \ - \
\ @@ -3381,10 +3381,10 @@ if(!this.timezone){this.timezone='UTC'}}}(window.jQuery);+function($){"use stric this.initFilterNumber()} FilterWidget.prototype.initFilterNumber=function(){var self=this this.$el.on('show.oc.popover','a.filter-scope-number',function(event){self.initNumberInputs($(this).hasClass('range')) -$(event.relatedTarget).on('click','#controlFilterPopoverNum [data-trigger="filter"]',function(e){e.preventDefault() +$(event.relatedTarget).on('click','#controlFilterPopoverNum [data-filter-action="filter"]',function(e){e.preventDefault() e.stopPropagation() self.filterByNumber()}) -$(event.relatedTarget).on('click','#controlFilterPopoverNum [data-trigger="clear"]',function(e){e.preventDefault() +$(event.relatedTarget).on('click','#controlFilterPopoverNum [data-filter-action="clear"]',function(e){e.preventDefault() e.stopPropagation() self.filterByNumber(true)})}) this.$el.on('hide.oc.popover','a.filter-scope-number',function(){var $scope=$(this) @@ -3416,10 +3416,10 @@ FilterWidget.prototype.getPopoverNumberTemplate=function(){return' placeholder="{{ number_placeholder }}" /> \ \
\ - \ - \
\ @@ -3456,10 +3456,10 @@ FilterWidget.prototype.getPopoverNumberRangeTemplate=function(){return' \ \
\ - \ - \
\ From 20cca6a00bfbe14083cbb6261aac10ada48c0ce5 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Mon, 25 Nov 2019 00:59:00 -0500 Subject: [PATCH 112/157] Add missing documentation comment blocks for fired events (#4788) Credit to @mjauvin. --- modules/backend/classes/Controller.php | 20 ++++++++++++-- modules/backend/classes/NavigationManager.php | 14 ++++++++-- modules/backend/models/User.php | 12 +++++++++ modules/backend/routes.php | 25 ++++++++++++++--- modules/cms/routes.php | 25 ++++++++++++++--- modules/cms/twig/Extension.php | 13 +++++++++ modules/system/classes/CombineAssets.php | 27 +++++++++++++++---- modules/system/classes/SettingsManager.php | 13 +++++++-- modules/system/traits/ConfigMaker.php | 15 +++++++++-- 9 files changed, 143 insertions(+), 21 deletions(-) diff --git a/modules/backend/classes/Controller.php b/modules/backend/classes/Controller.php index d019150cbd..01ac494f5e 100644 --- a/modules/backend/classes/Controller.php +++ b/modules/backend/classes/Controller.php @@ -242,8 +242,24 @@ public function run($action = null, $params = []) } } - /* - * Extensibility + /** + * @event backend.page.beforeDisplay + * Provides an opportunity to override backend page content + * + * Example usage: + * + * Event::listen('backend.page.beforeDisplay', function ((\Backend\Classes\Controller) $backendController, (string) $action, (array) $params) { + * trace_log('redirect all backend pages to google'); + * return \Redirect::to('https://google.com'); + * }); + * + * Or + * + * $backendController->bindEvent('page.beforeDisplay', function ((string) $action, (array) $params) { + * trace_log('redirect all backend pages to google'); + * return \Redirect::to('https://google.com'); + * }); + * */ if ($event = $this->fireSystemEvent('backend.page.beforeDisplay', [$action, $params])) { return $event; diff --git a/modules/backend/classes/NavigationManager.php b/modules/backend/classes/NavigationManager.php index d91915a40d..59003f7f0c 100644 --- a/modules/backend/classes/NavigationManager.php +++ b/modules/backend/classes/NavigationManager.php @@ -100,8 +100,18 @@ protected function loadItems() $this->registerMenuItems($id, $items); } - /* - * Extensibility + /** + * @event backend.menu.extendItems + * Provides an opportunity to manipulate the backend navigation + * + * Example usage: + * + * Event::listen('backend.menu.extendItems', function ((\Backend\Classes\NavigationManager) $navigationManager) { + * $navigationManager->addMainMenuItems(...) + * $navigationManager->addSideMenuItems(...) + * $navigationManager->removeMainMenuItem(...) + * }); + * */ Event::fire('backend.menu.extendItems', [$this]); diff --git a/modules/backend/models/User.php b/modules/backend/models/User.php index f527f58ca3..f2b54442c8 100644 --- a/modules/backend/models/User.php +++ b/modules/backend/models/User.php @@ -136,6 +136,18 @@ public function afterCreate() public function afterLogin() { parent::afterLogin(); + + /** + * @event backend.user.login + * Provides an opportunity to interact with the Backend User model after the user has logged in + * + * Example usage: + * + * Event::listen('backend.user.login', function ((\Backend\Models\User) $user) { + * Flash::success(sprintf('Welcome %s!', $user->getFullNameAttribute())); + * }); + * + */ Event::fire('backend.user.login', [$this]); } diff --git a/modules/backend/routes.php b/modules/backend/routes.php index c89ff91a43..81904802f8 100644 --- a/modules/backend/routes.php +++ b/modules/backend/routes.php @@ -4,8 +4,17 @@ * Register Backend routes before all user routes. */ App::before(function ($request) { - /* - * Extensibility + + /** + * @event backend.beforeRoute + * Fires before backend routes get added + * + * Example usage: + * + * Event::listen('backend.beforeRoute', function () { + * // your code here + * }); + * */ Event::fire('backend.beforeRoute'); @@ -25,8 +34,16 @@ */ Route::any(Config::get('cms.backendUri', 'backend'), 'Backend\Classes\BackendController@run')->middleware('web'); - /* - * Extensibility + /** + * @event backend.route + * Fires after backend routes have been added + * + * Example usage: + * + * Event::listen('backend.route', function () { + * // your code here + * }); + * */ Event::fire('backend.route'); }); diff --git a/modules/cms/routes.php b/modules/cms/routes.php index 9826a6deca..76f35c4b3e 100644 --- a/modules/cms/routes.php +++ b/modules/cms/routes.php @@ -4,8 +4,17 @@ * Register CMS routes before all user routes. */ App::before(function ($request) { - /* - * Extensibility + + /** + * @event cms.beforeRoute + * Fires before cms routes get added + * + * Example usage: + * + * Event::listen('cms.beforeRoute', function () { + * // your code here + * }); + * */ Event::fire('cms.beforeRoute'); @@ -15,8 +24,16 @@ */ Route::any('{slug}', 'Cms\Classes\CmsController@run')->where('slug', '(.*)?')->middleware('web'); - /* - * Extensibility + /** + * @event cms.route + * Fires after cms routes get added + * + * Example usage: + * + * Event::listen('cms.route', function () { + * // your code here + * }); + * */ Event::fire('cms.route'); }); diff --git a/modules/cms/twig/Extension.php b/modules/cms/twig/Extension.php index 8dfc67de5d..af95e6b0b7 100644 --- a/modules/cms/twig/Extension.php +++ b/modules/cms/twig/Extension.php @@ -193,6 +193,19 @@ public function displayBlock($name, $default = null) return $default; } + /** + * @event cms.block.render + * Provides an opportunity to modify the rendered block content + * + * Example usage: + * + * Event::listen('cms.block.render', function ((string) $name, (string) $result) { + * if ($name === 'myBlockName') { + * return 'my custom content'; + * } + * }); + * + */ if ($event = Event::fire('cms.block.render', [$name, $result], true)) { $result = $event; } diff --git a/modules/system/classes/CombineAssets.php b/modules/system/classes/CombineAssets.php index 79644123e9..bc5d1d6ded 100644 --- a/modules/system/classes/CombineAssets.php +++ b/modules/system/classes/CombineAssets.php @@ -411,8 +411,16 @@ protected function prepareRequest(array $assets, $localPath = null) */ protected function prepareCombiner(array $assets, $rewritePath = null) { - /* - * Extensibility + /** + * @event cms.combiner.beforePrepare + * Provides an opportunity to interact with the asset combiner before assets are combined + * + * Example usage: + * + * Event::listen('cms.combiner.beforePrepare', function ((\System\Classes\CombineAssets) $assetCombiner, (array) $assets) { + * $assetCombiner->registerFilter(...) + * }); + * */ Event::fire('cms.combiner.beforePrepare', [$this, $assets]); @@ -809,10 +817,19 @@ protected function getCacheKey(array $assets) $cacheKey .= $this->getDeepHashFromAssets($assets); } - /* - * Extensibility - */ $dataHolder = (object) ['key' => $cacheKey]; + + /** + * @event cms.combiner.getCacheKey + * Provides an opportunity to modify the asset combiner's cache key + * + * Example usage: + * + * Event::listen('cms.combiner.getCacheKey', function ((\System\Classes\CombineAssets) $assetCombiner, (stdClass) $dataHolder) { + * $dataHolder->key = rand(); + * }); + * + */ Event::fire('cms.combiner.getCacheKey', [$this, $dataHolder]); $cacheKey = $dataHolder->key; diff --git a/modules/system/classes/SettingsManager.php b/modules/system/classes/SettingsManager.php index eee21607b1..67873a78ef 100644 --- a/modules/system/classes/SettingsManager.php +++ b/modules/system/classes/SettingsManager.php @@ -109,8 +109,17 @@ protected function loadItems() $this->registerSettingItems($id, $items); } - /* - * Extensibility + /** + * @event system.settings.extendItems + * Provides an opportunity to manipulate the system settings manager + * + * Example usage: + * + * Event::listen('system.settings.extendItems', function ((\System\Classes\SettingsManager) $settingsManager) { + * $settingsManager->addSettingItem(...) + * $settingsManager->removeSettingItem(...) + * }); + * */ Event::fire('system.settings.extendItems', [$this]); diff --git a/modules/system/traits/ConfigMaker.php b/modules/system/traits/ConfigMaker.php index 9a78be8c35..12fc45e68a 100644 --- a/modules/system/traits/ConfigMaker.php +++ b/modules/system/traits/ConfigMaker.php @@ -67,8 +67,19 @@ public function makeConfig($configFile = [], $requiredConfig = []) $config = Yaml::parseFile($configFile); - /* - * Extensibility + /** + * @event system.extendConfigFile + * Provides an opportunity to modify config files + * + * Example usage: + * + * Event::listen('system.extendConfigFile', function ((string) $path, (array) $config) { + * if ($path === '/plugins/author/plugin-name/controllers/mycontroller/config_relation.yaml') { + * unset($config['property_value']['view']['recordUrl']); + * return $config; + * } + * }); + * */ $publicFile = File::localToPublic($configFile); if ($results = Event::fire('system.extendConfigFile', [$publicFile, $config])) { From 84edf331f45aa8c1cdcf4e0ca0be7abb62d5282b Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Mon, 25 Nov 2019 16:58:39 +1100 Subject: [PATCH 113/157] Add touch events back to modernizer --- modules/system/assets/ui/vendor/modernizr/modernizr.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/modules/system/assets/ui/vendor/modernizr/modernizr.js b/modules/system/assets/ui/vendor/modernizr/modernizr.js index 60edf6d9d9..0db1bd6c62 100644 --- a/modules/system/assets/ui/vendor/modernizr/modernizr.js +++ b/modules/system/assets/ui/vendor/modernizr/modernizr.js @@ -1,5 +1,3 @@ -/*! - * modernizr v3.7.1 - * Build https://modernizr.com/download?-applicationcache-audio-audioloop-backgroundsize-bgsizecover-borderimage-borderradius-boxshadow-boxsizing-canvas-canvastext-cssanimations-csscalc-csscolumns-cssgradients-cssgrid_cssgridlegacy-cssreflections-csstransforms-csstransforms3d-csstransformslevel2-csstransitions-cssvhunit-cssvmaxunit-cssvminunit-cssvwunit-flexbox-flexboxlegacy-flexboxtweener-flexwrap-fontdisplay-fontface-forcetouch-generatedcontent-geolocation-hashchange-history-hsla-indexeddb-indexeddbblob-inlinesvg-input-inputformaction-inputformenctype-inputformmethod-inputformnovalidate-inputformtarget-inputsearchevent-inputtypes-localstorage-multiplebgs-opacity-postmessage-preserve3d-rgba-sessionstorage-smil-srcset-svg-svgasimg-svgclippaths-svgfilters-svgforeignobject-textshadow-touchevents-video-videocrossorigin-videoloop-videopreload-webaudio-webgl-webglextensions-websockets-websocketsbinary-websqldatabase-webworkers-domprefixes-hasevent-mq-prefixes-printshiv-setclasses-testallprops-testprop-teststyles-dontmin -*/ -!function(f,u,p){var s=[],e={_version:"3.7.1",_config:{classPrefix:"",enableClasses:!0,enableJSClass:!0,usePrefixes:!0},_q:[],on:function(e,t){var n=this;setTimeout(function(){t(n[e])},0)},addTest:function(e,t,n){s.push({name:e,fn:t,options:n})},addAsyncTest:function(e){s.push({name:null,fn:e})}},c=function(){};c.prototype=e,c=new c;var d=[];function m(e,t){return typeof e===t}var h=u.documentElement,g="svg"===h.nodeName.toLowerCase();function a(e){var t=h.className,n=c._config.classPrefix||"";if(g&&(t=t.baseVal),c._config.enableJSClass){var r=new RegExp("(^|\\s)"+n+"no-js(\\s|$)");t=t.replace(r,"$1"+n+"js$2")}c._config.enableClasses&&(0",r.insertBefore(n.lastChild,r.firstChild)}function f(){var e=h.elements;return"string"==typeof e?e.split(" "):e}function p(e){var t=c[e[r]];return t||(t={},d++,e[r]=d,c[d]=t),t}function l(e,t,n){return t||(t=i),s?t.createElement(e):(n||(n=p(t)),!(r=n.cache[e]?n.cache[e].cloneNode():a.test(e)?(n.cache[e]=n.createElem(e)).cloneNode():n.createElem(e)).canHaveChildren||o.test(e)||r.tagUrn?r:n.frag.appendChild(r));var r}function m(e){e||(e=i);var t=p(e);return!h.shivCSS||n||t.hasCSS||(t.hasCSS=!!u(e,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),s||function(t,n){n.cache||(n.cache={},n.createElem=t.createElement,n.createFrag=t.createDocumentFragment,n.frag=n.createFrag()),t.createElement=function(e){return h.shivMethods?l(e,t,n):n.createElem(e)},t.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+f().join().replace(/[\w\-:]+/g,function(e){return n.createElem(e),n.frag.createElement(e),'c("'+e+'")'})+");return n}")(h,n.frag)}(e,t),e}!function(){try{var e=i.createElement("a");e.innerHTML="",n="hidden"in e,s=1==e.childNodes.length||function(){i.createElement("a");var e=i.createDocumentFragment();return void 0===e.cloneNode||void 0===e.createDocumentFragment||void 0===e.createElement}()}catch(e){s=n=!0}}();var h={elements:t.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:"3.7.3",shivCSS:!1!==t.shivCSS,supportsUnknownElements:s,shivMethods:!1!==t.shivMethods,type:"default",shivDocument:m,createElement:l,createDocumentFragment:function(e,t){if(e||(e=i),s)return e.createDocumentFragment();for(var n=(t=t||p(e)).frag.cloneNode(),r=0,o=f(),a=o.length;r+~])("+f().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),a="$1"+y+"\\:$2";r--;)(t=n[r]=n[r].split("}"))[t.length-1]=t[t.length-1].replace(o,a),n[r]=t.join("}");return n.join("{")}(o.reverse().join("")),c=function(e){for(var t,n=e.getElementsByTagName("*"),r=n.length,o=RegExp("^(?:"+f().join("|")+")$","i"),a=[];r--;)t=n[r],o.test(t.nodeName)&&a.push(t.applyElement(T(t)));return a}(s),d=u(s,o)}),n.attachEvent("onafterprint",function(){!function(e){for(var t=e.length;t--;)e[t].removeNode()}(c),clearTimeout(e._removeSheetTimer),e._removeSheetTimer=setTimeout(l,500)}),s.printShived=!0,s}h.type+=" print",(h.shivPrint=x)(i),"object"==typeof module&&module.exports&&(module.exports=h)}(void 0!==f?f:this,u);var T=e._config.usePrefixes?t.split(" "):[];function x(e,t){return!!~(""+e).indexOf(t)}e._cssomPrefixes=T;var w={elem:v("modernizr")};c._q.push(function(){delete w.elem});var S={style:w.elem.style};function C(e){return e.replace(/([A-Z])/g,function(e,t){return"-"+t.toLowerCase()}).replace(/^ms-/,"-ms-")}function E(e,t,n){var r;if("getComputedStyle"in f){r=getComputedStyle.call(f,e,t);var o=f.console;if(null!==r)n&&(r=r.getPropertyValue(n));else if(o)o[o.error?"error":"log"].call(o,"getComputedStyle returning null, its possible modernizr test results are inaccurate")}else r=!t&&e.currentStyle&&e.currentStyle[n];return r}function k(e){return e.replace(/([a-z])-([a-z])/g,function(e,t,n){return t+n.toUpperCase()}).replace(/^-/,"")}function _(e,t,n,r){if(r=!m(r,"undefined")&&r,!m(n,"undefined")){var o=function(e,t){var n=e.length;if("CSS"in f&&"supports"in f.CSS){for(;n--;)if(f.CSS.supports(C(e[n]),t))return!0;return!1}if("CSSSupportsRule"in f){for(var r=[];n--;)r.push("("+C(e[n])+":"+t+")");return y("@supports ("+(r=r.join(" or "))+") { #modernizr { position: absolute; } }",function(e){return"absolute"===E(e,null,"position")})}return p}(e,n);if(!m(o,"undefined"))return o}for(var a,i,s,d,c,l=["modernizr","tspan","samp"];!S.style&&l.length;)a=!0,S.modElem=v(l.shift()),S.style=S.modElem.style;function u(){a&&(delete S.style,delete S.modElem)}for(s=e.length,i=0;if;f++)if(m=e[f],g=G.style[m],s(m,"-")&&(m=d(m)),G.style[m]!==n){if(a||r(o,"undefined"))return c(),"pfx"==t?m:!0;try{G.style[m]=o}catch(y){}if(G.style[m]!=g)return c(),"pfx"==t?m:!0}return c(),!1}function y(e,t,n,o,a){var i=e.charAt(0).toUpperCase()+e.slice(1),s=(e+" "+U.join(i+" ")+i).split(" ");return r(t,"string")||r(t,"undefined")?v(s,t,o,a):(s=(e+" "+O.join(i+" ")+i).split(" "),p(s,t,n))}function b(e,t,r){return y(e,n,n,t,r)}function T(e,t){var n=e.deleteDatabase(t);n.onsuccess=function(){u("indexeddb.deletedatabase",!0)},n.onerror=function(){u("indexeddb.deletedatabase",!1)}}var x=[],w=[],S={_version:"3.6.0",_config:{classPrefix:"",enableClasses:!0,enableJSClass:!0,usePrefixes:!0},_q:[],on:function(e,t){var n=this;setTimeout(function(){t(n[e])},0)},addTest:function(e,t,n){w.push({name:e,fn:t,options:n})},addAsyncTest:function(e){w.push({name:null,fn:e})}},Modernizr=function(){};Modernizr.prototype=S,Modernizr=new Modernizr,Modernizr.addTest("applicationcache","applicationCache"in e),Modernizr.addTest("geolocation","geolocation"in navigator),Modernizr.addTest("history",function(){var t=navigator.userAgent;return-1===t.indexOf("Android 2.")&&-1===t.indexOf("Android 4.0")||-1===t.indexOf("Mobile Safari")||-1!==t.indexOf("Chrome")||-1!==t.indexOf("Windows Phone")||"file:"===location.protocol?e.history&&"pushState"in e.history:!1}),Modernizr.addTest("postmessage","postMessage"in e),Modernizr.addTest("svg",!!t.createElementNS&&!!t.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect);var C=!1;try{C="WebSocket"in e&&2===e.WebSocket.CLOSING}catch(E){}Modernizr.addTest("websockets",C),Modernizr.addTest("localstorage",function(){var e="modernizr";try{return localStorage.setItem(e,e),localStorage.removeItem(e),!0}catch(t){return!1}}),Modernizr.addTest("sessionstorage",function(){var e="modernizr";try{return sessionStorage.setItem(e,e),sessionStorage.removeItem(e),!0}catch(t){return!1}}),Modernizr.addTest("websqldatabase","openDatabase"in e),Modernizr.addTest("webworkers","Worker"in e);var _=S._config.usePrefixes?" -webkit- -moz- -o- -ms- ".split(" "):["",""];S._prefixes=_;var k=t.documentElement,P="svg"===k.nodeName.toLowerCase();P||!function(e,t){function n(e,t){var n=e.createElement("p"),r=e.getElementsByTagName("head")[0]||e.documentElement;return n.innerHTML="x",r.insertBefore(n.lastChild,r.firstChild)}function r(){var e=b.elements;return"string"==typeof e?e.split(" "):e}function o(e,t){var n=b.elements;"string"!=typeof n&&(n=n.join(" ")),"string"!=typeof e&&(e=e.join(" ")),b.elements=n+" "+e,l(t)}function a(e){var t=y[e[h]];return t||(t={},v++,e[h]=v,y[v]=t),t}function i(e,n,r){if(n||(n=t),u)return n.createElement(e);r||(r=a(n));var o;return o=r.cache[e]?r.cache[e].cloneNode():g.test(e)?(r.cache[e]=r.createElem(e)).cloneNode():r.createElem(e),!o.canHaveChildren||m.test(e)||o.tagUrn?o:r.frag.appendChild(o)}function s(e,n){if(e||(e=t),u)return e.createDocumentFragment();n=n||a(e);for(var o=n.frag.cloneNode(),i=0,s=r(),c=s.length;c>i;i++)o.createElement(s[i]);return o}function c(e,t){t.cache||(t.cache={},t.createElem=e.createElement,t.createFrag=e.createDocumentFragment,t.frag=t.createFrag()),e.createElement=function(n){return b.shivMethods?i(n,e,t):t.createElem(n)},e.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+r().join().replace(/[\w\-:]+/g,function(e){return t.createElem(e),t.frag.createElement(e),'c("'+e+'")'})+");return n}")(b,t.frag)}function l(e){e||(e=t);var r=a(e);return!b.shivCSS||d||r.hasCSS||(r.hasCSS=!!n(e,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),u||c(e,r),e}var d,u,f="3.7.3",p=e.html5||{},m=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,g=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,h="_html5shiv",v=0,y={};!function(){try{var e=t.createElement("a");e.innerHTML="",d="hidden"in e,u=1==e.childNodes.length||function(){t.createElement("a");var e=t.createDocumentFragment();return"undefined"==typeof e.cloneNode||"undefined"==typeof e.createDocumentFragment||"undefined"==typeof e.createElement}()}catch(n){d=!0,u=!0}}();var b={elements:p.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:f,shivCSS:p.shivCSS!==!1,supportsUnknownElements:u,shivMethods:p.shivMethods!==!1,type:"default",shivDocument:l,createElement:i,createDocumentFragment:s,addElements:o};e.html5=b,l(t),"object"==typeof module&&module.exports&&(module.exports=b)}("undefined"!=typeof e?e:this,t);var N="Moz O ms Webkit",O=S._config.usePrefixes?N.toLowerCase().split(" "):[];S._domPrefixes=O;var z=function(){function e(e,t){var o;return e?(t&&"string"!=typeof t||(t=i(t||"div")),e="on"+e,o=e in t,!o&&r&&(t.setAttribute||(t=i("div")),t.setAttribute(e,""),o="function"==typeof t[e],t[e]!==n&&(t[e]=n),t.removeAttribute(e)),o):!1}var r=!("onblur"in t.documentElement);return e}();S.hasEvent=z,Modernizr.addTest("hashchange",function(){return z("hashchange",e)===!1?!1:t.documentMode===n||t.documentMode>7}),Modernizr.addTest("audio",function(){var e=i("audio"),t=!1;try{t=!!e.canPlayType,t&&(t=new Boolean(t),t.ogg=e.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),t.mp3=e.canPlayType('audio/mpeg; codecs="mp3"').replace(/^no$/,""),t.opus=e.canPlayType('audio/ogg; codecs="opus"')||e.canPlayType('audio/webm; codecs="opus"').replace(/^no$/,""),t.wav=e.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),t.m4a=(e.canPlayType("audio/x-m4a;")||e.canPlayType("audio/aac;")).replace(/^no$/,""))}catch(n){}return t}),Modernizr.addTest("canvas",function(){var e=i("canvas");return!(!e.getContext||!e.getContext("2d"))}),Modernizr.addTest("canvastext",function(){return Modernizr.canvas===!1?!1:"function"==typeof i("canvas").getContext("2d").fillText}),Modernizr.addTest("video",function(){var e=i("video"),t=!1;try{t=!!e.canPlayType,t&&(t=new Boolean(t),t.ogg=e.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),t.h264=e.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),t.webm=e.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,""),t.vp9=e.canPlayType('video/webm; codecs="vp9"').replace(/^no$/,""),t.hls=e.canPlayType('application/x-mpegURL; codecs="avc1.42E01E"').replace(/^no$/,""))}catch(n){}return t}),Modernizr.addTest("webgl",function(){var t=i("canvas"),n="probablySupportsContext"in t?"probablySupportsContext":"supportsContext";return n in t?t[n]("webgl")||t[n]("experimental-webgl"):"WebGLRenderingContext"in e}),Modernizr.addTest("cssgradients",function(){for(var e,t="background-image:",n="gradient(linear,left top,right bottom,from(#9f9),to(white));",r="",o=0,a=_.length-1;a>o;o++)e=0===o?"to ":"",r+=t+_[o]+"linear-gradient("+e+"left top, #9f9, white);";Modernizr._config.usePrefixes&&(r+=t+"-webkit-"+n);var s=i("a"),c=s.style;return c.cssText=r,(""+c.backgroundImage).indexOf("gradient")>-1}),Modernizr.addTest("multiplebgs",function(){var e=i("a").style;return e.cssText="background:url(https://),url(https://),red url(https://)",/(url\s*\(.*?){3}/.test(e.background)}),Modernizr.addTest("opacity",function(){var e=i("a").style;return e.cssText=_.join("opacity:.55;"),/^0.55$/.test(e.opacity)}),Modernizr.addTest("rgba",function(){var e=i("a").style;return e.cssText="background-color:rgba(150,255,150,.5)",(""+e.backgroundColor).indexOf("rgba")>-1}),Modernizr.addTest("inlinesvg",function(){var e=i("div");return e.innerHTML="","http://www.w3.org/2000/svg"==("undefined"!=typeof SVGRect&&e.firstChild&&e.firstChild.namespaceURI)});var R=i("input"),A="autocomplete autofocus list placeholder max min multiple pattern required step".split(" "),M={};Modernizr.input=function(t){for(var n=0,r=t.length;r>n;n++)M[t[n]]=!!(t[n]in R);return M.list&&(M.list=!(!i("datalist")||!e.HTMLDataListElement)),M}(A);var $="search tel url email datetime date month week time datetime-local number range color".split(" "),B={};Modernizr.inputtypes=function(e){for(var r,o,a,i=e.length,s="1)",c=0;i>c;c++)R.setAttribute("type",r=e[c]),a="text"!==R.type&&"style"in R,a&&(R.value=s,R.style.cssText="position:absolute;visibility:hidden;",/^range$/.test(r)&&R.style.WebkitAppearance!==n?(k.appendChild(R),o=t.defaultView,a=o.getComputedStyle&&"textfield"!==o.getComputedStyle(R,null).WebkitAppearance&&0!==R.offsetHeight,k.removeChild(R)):/^(search|tel)$/.test(r)||(a=/^(url|email)$/.test(r)?R.checkValidity&&R.checkValidity()===!1:R.value!=s)),B[e[c]]=!!a;return B}($),Modernizr.addTest("hsla",function(){var e=i("a").style;return e.cssText="background-color:hsla(120,40%,100%,.5)",s(e.backgroundColor,"rgba")||s(e.backgroundColor,"hsla")});var j="CSS"in e&&"supports"in e.CSS,L="supportsCSS"in e;Modernizr.addTest("supports",j||L);var D={}.toString;Modernizr.addTest("svgclippaths",function(){return!!t.createElementNS&&/SVGClipPath/.test(D.call(t.createElementNS("http://www.w3.org/2000/svg","clipPath")))}),Modernizr.addTest("smil",function(){return!!t.createElementNS&&/SVGAnimate/.test(D.call(t.createElementNS("http://www.w3.org/2000/svg","animate")))});var F=function(){var t=e.matchMedia||e.msMatchMedia;return t?function(e){var n=t(e);return n&&n.matches||!1}:function(t){var n=!1;return l("@media "+t+" { #modernizr { position: absolute; } }",function(t){n="absolute"==(e.getComputedStyle?e.getComputedStyle(t,null):t.currentStyle).position}),n}}();S.mq=F;var I=S.testStyles=l,W=function(){var e=navigator.userAgent,t=e.match(/w(eb)?osbrowser/gi),n=e.match(/windows phone/gi)&&e.match(/iemobile\/([0-9])+/gi)&&parseFloat(RegExp.$1)>=9;return t||n}();W?Modernizr.addTest("fontface",!1):I('@font-face {font-family:"font";src:url("https://")}',function(e,n){var r=t.getElementById("smodernizr"),o=r.sheet||r.styleSheet,a=o?o.cssRules&&o.cssRules[0]?o.cssRules[0].cssText:o.cssText||"":"",i=/src/i.test(a)&&0===a.indexOf(n.split(" ")[0]);Modernizr.addTest("fontface",i)}),I('#modernizr{font:0/0 a}#modernizr:after{content:":)";visibility:hidden;font:7px/1 a}',function(e){Modernizr.addTest("generatedcontent",e.offsetHeight>=6)}),Modernizr.addTest("touchevents",function(){var n;if("ontouchstart"in e||e.DocumentTouch&&t instanceof DocumentTouch)n=!0;else{var r=["@media (",_.join("touch-enabled),("),"heartz",")","{#modernizr{top:9px;position:absolute}}"].join("");I(r,function(e){n=9===e.offsetTop})}return n});var U=S._config.usePrefixes?N.split(" "):[];S._cssomPrefixes=U;var V=function(t){var r,o=_.length,a=e.CSSRule;if("undefined"==typeof a)return n;if(!t)return!1;if(t=t.replace(/^@/,""),r=t.replace(/-/g,"_").toUpperCase()+"_RULE",r in a)return"@"+t;for(var i=0;o>i;i++){var s=_[i],c=s.toUpperCase()+"_"+r;if(c in a)return"@-"+s.toLowerCase()+"-"+t}return!1};S.atRule=V;var q;!function(){var e={}.hasOwnProperty;q=r(e,"undefined")||r(e.call,"undefined")?function(e,t){return t in e&&r(e.constructor.prototype[t],"undefined")}:function(t,n){return e.call(t,n)}}(),S._l={},S.on=function(e,t){this._l[e]||(this._l[e]=[]),this._l[e].push(t),Modernizr.hasOwnProperty(e)&&setTimeout(function(){Modernizr._trigger(e,Modernizr[e])},0)},S._trigger=function(e,t){if(this._l[e]){var n=this._l[e];setTimeout(function(){var e,r;for(e=0;e Date: Thu, 28 Nov 2019 09:21:03 +0800 Subject: [PATCH 114/157] Parenthesise some double ternary conditions in Asset Combiner. Improve compatibility with PHP 7.4, where "Unparenthesized `a ? b : c ?: d` is deprecated" Fixes #4790. --- .github/workflows/tests.yml | 2 +- modules/system/classes/CombineAssets.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b3ce5ca088..8b73a18b90 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,7 +13,7 @@ jobs: strategy: max-parallel: 6 matrix: - phpVersions: ['7.1', '7.2', '7.3'] + phpVersions: ['7.1', '7.2', '7.3', '7.4'] fail-fast: false name: PHP ${{ matrix.phpVersions }} steps: diff --git a/modules/system/classes/CombineAssets.php b/modules/system/classes/CombineAssets.php index bc5d1d6ded..87a9d1d8fa 100644 --- a/modules/system/classes/CombineAssets.php +++ b/modules/system/classes/CombineAssets.php @@ -428,7 +428,7 @@ protected function prepareCombiner(array $assets, $rewritePath = null) $filesSalt = null; foreach ($assets as $asset) { $filters = $this->getFilters(File::extension($asset)) ?: []; - $path = file_exists($asset) ? $asset : File::symbolizePath($asset, null) ?: $this->localPath . $asset; + $path = file_exists($asset) ? $asset : (File::symbolizePath($asset, null) ?: $this->localPath . $asset); $files[] = new FileAsset($path, $filters, public_path()); $filesSalt .= $this->localPath . $asset; } @@ -482,7 +482,7 @@ protected function getDeepHashFromAssets($assets) $key = ''; $assetFiles = array_map(function ($file) { - return file_exists($file) ? $file : File::symbolizePath($file, null) ?: $this->localPath . $file; + return file_exists($file) ? $file : (File::symbolizePath($file, null) ?: $this->localPath . $file); }, $assets); foreach ($assetFiles as $file) { From 9068d629613dd700b2ad6030b5a19dfde07f4379 Mon Sep 17 00:00:00 2001 From: Ben Thomson Date: Thu, 28 Nov 2019 09:25:10 +0800 Subject: [PATCH 115/157] Ensure necessary PHP extensions are installed with unit tests --- .github/workflows/tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8b73a18b90..5369874010 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -23,6 +23,7 @@ jobs: uses: shivammathur/setup-php@master with: php-version: ${{ matrix.phpVersions }} + extension-csv: mbstring, intl - name: Install Composer dependencies run: composer install --no-interaction --no-progress --no-suggest - name: Reset October modules and library From 4de2ef8c8a5d87b2fbb09448e981e0313ee38a4d Mon Sep 17 00:00:00 2001 From: Ben Thomson Date: Thu, 28 Nov 2019 12:48:56 +0800 Subject: [PATCH 116/157] Delay running post-update Composer scripts in automated tests Allows us to reset the October codebase to what's in Git *before* running these tasks. --- .github/workflows/tests.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5369874010..18143af927 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -25,7 +25,7 @@ jobs: php-version: ${{ matrix.phpVersions }} extension-csv: mbstring, intl - name: Install Composer dependencies - run: composer install --no-interaction --no-progress --no-suggest + run: composer install --no-interaction --no-progress --no-suggest --no-scripts - name: Reset October modules and library run: | git reset --hard HEAD @@ -34,6 +34,10 @@ jobs: unzip ./vendor/october/develop.zip -d ./vendor/october mv ./vendor/october/library-develop ./vendor/october/rain composer dump-autoload + - name: Run post-update Composer scripts + run: | + php artisan october:util set build + php artisan package:discover - name: Run Linting and Tests run: | ./vendor/bin/parallel-lint --exclude vendor --exclude storage --exclude tests/fixtures/plugins/testvendor/goto/Plugin.php . From 4a47200a8210523779ac2f5dbe441fc706870a6b Mon Sep 17 00:00:00 2001 From: Ben Thomson Date: Thu, 28 Nov 2019 12:52:31 +0800 Subject: [PATCH 117/157] Add a few more PHP extensions into the automated tests --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 18143af927..31d195a70e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -23,7 +23,7 @@ jobs: uses: shivammathur/setup-php@master with: php-version: ${{ matrix.phpVersions }} - extension-csv: mbstring, intl + extension-csv: mbstring, intl, gd, xml - name: Install Composer dependencies run: composer install --no-interaction --no-progress --no-suggest --no-scripts - name: Reset October modules and library From 2a47fdad9e62d80261c39572e4ae37b221214c72 Mon Sep 17 00:00:00 2001 From: Ben Thomson Date: Thu, 28 Nov 2019 12:57:36 +0800 Subject: [PATCH 118/157] Include SQLite in automated tests --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 31d195a70e..072b795dac 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -23,7 +23,7 @@ jobs: uses: shivammathur/setup-php@master with: php-version: ${{ matrix.phpVersions }} - extension-csv: mbstring, intl, gd, xml + extension-csv: mbstring, intl, gd, xml, sqlite - name: Install Composer dependencies run: composer install --no-interaction --no-progress --no-suggest --no-scripts - name: Reset October modules and library From 8ebb2973be0d58347008fbef5950f76c2862ea62 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Thu, 28 Nov 2019 21:03:32 +1100 Subject: [PATCH 119/157] Fixes touch events in sortable plugin Refs #4791 Refs #4777 Refs #3755 --- modules/system/assets/ui/storm-min.js | 14 +++++++------- .../ui/vendor/sortable/jquery-sortable.js | 17 ++++++++++------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/modules/system/assets/ui/storm-min.js b/modules/system/assets/ui/storm-min.js index a3881f4283..7576ace785 100644 --- a/modules/system/assets/ui/storm-min.js +++ b/modules/system/assets/ui/storm-min.js @@ -51,7 +51,7 @@ return this.renderTokens(token[4],context,partials,originalTemplate);};Writer.pr return this.renderTokens(this.parse(value),context,partials,value);};Writer.prototype.unescapedValue=function unescapedValue(token,context){var value=context.lookup(token[1]);if(value!=null) return value;};Writer.prototype.escapedValue=function escapedValue(token,context){var value=context.lookup(token[1]);if(value!=null) return mustache.escape(value);};Writer.prototype.rawValue=function rawValue(token){return token[1];};mustache.name='mustache.js';mustache.version='2.3.2';mustache.tags=['{{','}}'];var defaultWriter=new Writer();mustache.clearCache=function clearCache(){return defaultWriter.clearCache();};mustache.parse=function parse(template,tags){return defaultWriter.parse(template,tags);};mustache.render=function render(template,view,partials){if(typeof template!=='string'){throw new TypeError('Invalid template! Template should be a "string" '+'but "'+typeStr(template)+'" was given as the first '+'argument for mustache#render(template, view, partials)');} -return defaultWriter.render(template,view,partials);};mustache.to_html=function to_html(template,view,partials,send){var result=mustache.render(template,view,partials);if(isFunction(send)){send(result);}else{return result;}};mustache.escape=escapeHtml;mustache.Scanner=Scanner;mustache.Context=Context;mustache.Writer=Writer;return mustache;}));!function(f,u,p){var s=[],e={_version:"3.7.1",_config:{classPrefix:"",enableClasses:!0,enableJSClass:!0,usePrefixes:!0},_q:[],on:function(e,t){var n=this;setTimeout(function(){t(n[e])},0)},addTest:function(e,t,n){s.push({name:e,fn:t,options:n})},addAsyncTest:function(e){s.push({name:null,fn:e})}},c=function(){};c.prototype=e,c=new c;var d=[];function m(e,t){return typeof e===t}var h=u.documentElement,g="svg"===h.nodeName.toLowerCase();function a(e){var t=h.className,n=c._config.classPrefix||"";if(g&&(t=t.baseVal),c._config.enableJSClass){var r=new RegExp("(^|\\s)"+n+"no-js(\\s|$)");t=t.replace(r,"$1"+n+"js$2")}c._config.enableClasses&&(0",r.insertBefore(n.lastChild,r.firstChild)}function f(){var e=h.elements;return"string"==typeof e?e.split(" "):e}function p(e){var t=c[e[r]];return t||(t={},d++,e[r]=d,c[d]=t),t}function l(e,t,n){return t||(t=i),s?t.createElement(e):(n||(n=p(t)),!(r=n.cache[e]?n.cache[e].cloneNode():a.test(e)?(n.cache[e]=n.createElem(e)).cloneNode():n.createElem(e)).canHaveChildren||o.test(e)||r.tagUrn?r:n.frag.appendChild(r));var r}function m(e){e||(e=i);var t=p(e);return!h.shivCSS||n||t.hasCSS||(t.hasCSS=!!u(e,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),s||function(t,n){n.cache||(n.cache={},n.createElem=t.createElement,n.createFrag=t.createDocumentFragment,n.frag=n.createFrag()),t.createElement=function(e){return h.shivMethods?l(e,t,n):n.createElem(e)},t.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+f().join().replace(/[\w\-:]+/g,function(e){return n.createElem(e),n.frag.createElement(e),'c("'+e+'")'})+");return n}")(h,n.frag)}(e,t),e}!function(){try{var e=i.createElement("a");e.innerHTML="",n="hidden"in e,s=1==e.childNodes.length||function(){i.createElement("a");var e=i.createDocumentFragment();return void 0===e.cloneNode||void 0===e.createDocumentFragment||void 0===e.createElement}()}catch(e){s=n=!0}}();var h={elements:t.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:"3.7.3",shivCSS:!1!==t.shivCSS,supportsUnknownElements:s,shivMethods:!1!==t.shivMethods,type:"default",shivDocument:m,createElement:l,createDocumentFragment:function(e,t){if(e||(e=i),s)return e.createDocumentFragment();for(var n=(t=t||p(e)).frag.cloneNode(),r=0,o=f(),a=o.length;r+~])("+f().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),a="$1"+y+"\\:$2";r--;)(t=n[r]=n[r].split("}"))[t.length-1]=t[t.length-1].replace(o,a),n[r]=t.join("}");return n.join("{")}(o.reverse().join("")),c=function(e){for(var t,n=e.getElementsByTagName("*"),r=n.length,o=RegExp("^(?:"+f().join("|")+")$","i"),a=[];r--;)t=n[r],o.test(t.nodeName)&&a.push(t.applyElement(T(t)));return a}(s),d=u(s,o)}),n.attachEvent("onafterprint",function(){!function(e){for(var t=e.length;t--;)e[t].removeNode()}(c),clearTimeout(e._removeSheetTimer),e._removeSheetTimer=setTimeout(l,500)}),s.printShived=!0,s}h.type+=" print",(h.shivPrint=x)(i),"object"==typeof module&&module.exports&&(module.exports=h)}(void 0!==f?f:this,u);var T=e._config.usePrefixes?t.split(" "):[];function x(e,t){return!!~(""+e).indexOf(t)}e._cssomPrefixes=T;var w={elem:v("modernizr")};c._q.push(function(){delete w.elem});var S={style:w.elem.style};function C(e){return e.replace(/([A-Z])/g,function(e,t){return"-"+t.toLowerCase()}).replace(/^ms-/,"-ms-")}function E(e,t,n){var r;if("getComputedStyle"in f){r=getComputedStyle.call(f,e,t);var o=f.console;if(null!==r)n&&(r=r.getPropertyValue(n));else if(o)o[o.error?"error":"log"].call(o,"getComputedStyle returning null, its possible modernizr test results are inaccurate")}else r=!t&&e.currentStyle&&e.currentStyle[n];return r}function k(e){return e.replace(/([a-z])-([a-z])/g,function(e,t,n){return t+n.toUpperCase()}).replace(/^-/,"")}function _(e,t,n,r){if(r=!m(r,"undefined")&&r,!m(n,"undefined")){var o=function(e,t){var n=e.length;if("CSS"in f&&"supports"in f.CSS){for(;n--;)if(f.CSS.supports(C(e[n]),t))return!0;return!1}if("CSSSupportsRule"in f){for(var r=[];n--;)r.push("("+C(e[n])+":"+t+")");return y("@supports ("+(r=r.join(" or "))+") { #modernizr { position: absolute; } }",function(e){return"absolute"===E(e,null,"position")})}return p}(e,n);if(!m(o,"undefined"))return o}for(var a,i,s,d,c,l=["modernizr","tspan","samp"];!S.style&&l.length;)a=!0,S.modElem=v(l.shift()),S.style=S.modElem.style;function u(){a&&(delete S.style,delete S.modElem)}for(s=e.length,i=0;if;f++)if(m=e[f],g=G.style[m],s(m,"-")&&(m=d(m)),G.style[m]!==n){if(a||r(o,"undefined"))return c(),"pfx"==t?m:!0;try{G.style[m]=o}catch(y){}if(G.style[m]!=g)return c(),"pfx"==t?m:!0}return c(),!1}function y(e,t,n,o,a){var i=e.charAt(0).toUpperCase()+e.slice(1),s=(e+" "+U.join(i+" ")+i).split(" ");return r(t,"string")||r(t,"undefined")?v(s,t,o,a):(s=(e+" "+O.join(i+" ")+i).split(" "),p(s,t,n))}function b(e,t,r){return y(e,n,n,t,r)}function T(e,t){var n=e.deleteDatabase(t);n.onsuccess=function(){u("indexeddb.deletedatabase",!0)},n.onerror=function(){u("indexeddb.deletedatabase",!1)}}var x=[],w=[],S={_version:"3.6.0",_config:{classPrefix:"",enableClasses:!0,enableJSClass:!0,usePrefixes:!0},_q:[],on:function(e,t){var n=this;setTimeout(function(){t(n[e])},0)},addTest:function(e,t,n){w.push({name:e,fn:t,options:n})},addAsyncTest:function(e){w.push({name:null,fn:e})}},Modernizr=function(){};Modernizr.prototype=S,Modernizr=new Modernizr,Modernizr.addTest("applicationcache","applicationCache"in e),Modernizr.addTest("geolocation","geolocation"in navigator),Modernizr.addTest("history",function(){var t=navigator.userAgent;return-1===t.indexOf("Android 2.")&&-1===t.indexOf("Android 4.0")||-1===t.indexOf("Mobile Safari")||-1!==t.indexOf("Chrome")||-1!==t.indexOf("Windows Phone")||"file:"===location.protocol?e.history&&"pushState"in e.history:!1}),Modernizr.addTest("postmessage","postMessage"in e),Modernizr.addTest("svg",!!t.createElementNS&&!!t.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect);var C=!1;try{C="WebSocket"in e&&2===e.WebSocket.CLOSING}catch(E){}Modernizr.addTest("websockets",C),Modernizr.addTest("localstorage",function(){var e="modernizr";try{return localStorage.setItem(e,e),localStorage.removeItem(e),!0}catch(t){return!1}}),Modernizr.addTest("sessionstorage",function(){var e="modernizr";try{return sessionStorage.setItem(e,e),sessionStorage.removeItem(e),!0}catch(t){return!1}}),Modernizr.addTest("websqldatabase","openDatabase"in e),Modernizr.addTest("webworkers","Worker"in e);var _=S._config.usePrefixes?" -webkit- -moz- -o- -ms- ".split(" "):["",""];S._prefixes=_;var k=t.documentElement,P="svg"===k.nodeName.toLowerCase();P||!function(e,t){function n(e,t){var n=e.createElement("p"),r=e.getElementsByTagName("head")[0]||e.documentElement;return n.innerHTML="x",r.insertBefore(n.lastChild,r.firstChild)}function r(){var e=b.elements;return"string"==typeof e?e.split(" "):e}function o(e,t){var n=b.elements;"string"!=typeof n&&(n=n.join(" ")),"string"!=typeof e&&(e=e.join(" ")),b.elements=n+" "+e,l(t)}function a(e){var t=y[e[h]];return t||(t={},v++,e[h]=v,y[v]=t),t}function i(e,n,r){if(n||(n=t),u)return n.createElement(e);r||(r=a(n));var o;return o=r.cache[e]?r.cache[e].cloneNode():g.test(e)?(r.cache[e]=r.createElem(e)).cloneNode():r.createElem(e),!o.canHaveChildren||m.test(e)||o.tagUrn?o:r.frag.appendChild(o)}function s(e,n){if(e||(e=t),u)return e.createDocumentFragment();n=n||a(e);for(var o=n.frag.cloneNode(),i=0,s=r(),c=s.length;c>i;i++)o.createElement(s[i]);return o}function c(e,t){t.cache||(t.cache={},t.createElem=e.createElement,t.createFrag=e.createDocumentFragment,t.frag=t.createFrag()),e.createElement=function(n){return b.shivMethods?i(n,e,t):t.createElem(n)},e.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+r().join().replace(/[\w\-:]+/g,function(e){return t.createElem(e),t.frag.createElement(e),'c("'+e+'")'})+");return n}")(b,t.frag)}function l(e){e||(e=t);var r=a(e);return!b.shivCSS||d||r.hasCSS||(r.hasCSS=!!n(e,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),u||c(e,r),e}var d,u,f="3.7.3",p=e.html5||{},m=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,g=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,h="_html5shiv",v=0,y={};!function(){try{var e=t.createElement("a");e.innerHTML="",d="hidden"in e,u=1==e.childNodes.length||function(){t.createElement("a");var e=t.createDocumentFragment();return"undefined"==typeof e.cloneNode||"undefined"==typeof e.createDocumentFragment||"undefined"==typeof e.createElement}()}catch(n){d=!0,u=!0}}();var b={elements:p.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:f,shivCSS:p.shivCSS!==!1,supportsUnknownElements:u,shivMethods:p.shivMethods!==!1,type:"default",shivDocument:l,createElement:i,createDocumentFragment:s,addElements:o};e.html5=b,l(t),"object"==typeof module&&module.exports&&(module.exports=b)}("undefined"!=typeof e?e:this,t);var N="Moz O ms Webkit",O=S._config.usePrefixes?N.toLowerCase().split(" "):[];S._domPrefixes=O;var z=function(){function e(e,t){var o;return e?(t&&"string"!=typeof t||(t=i(t||"div")),e="on"+e,o=e in t,!o&&r&&(t.setAttribute||(t=i("div")),t.setAttribute(e,""),o="function"==typeof t[e],t[e]!==n&&(t[e]=n),t.removeAttribute(e)),o):!1}var r=!("onblur"in t.documentElement);return e}();S.hasEvent=z,Modernizr.addTest("hashchange",function(){return z("hashchange",e)===!1?!1:t.documentMode===n||t.documentMode>7}),Modernizr.addTest("audio",function(){var e=i("audio"),t=!1;try{t=!!e.canPlayType,t&&(t=new Boolean(t),t.ogg=e.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),t.mp3=e.canPlayType('audio/mpeg; codecs="mp3"').replace(/^no$/,""),t.opus=e.canPlayType('audio/ogg; codecs="opus"')||e.canPlayType('audio/webm; codecs="opus"').replace(/^no$/,""),t.wav=e.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),t.m4a=(e.canPlayType("audio/x-m4a;")||e.canPlayType("audio/aac;")).replace(/^no$/,""))}catch(n){}return t}),Modernizr.addTest("canvas",function(){var e=i("canvas");return!(!e.getContext||!e.getContext("2d"))}),Modernizr.addTest("canvastext",function(){return Modernizr.canvas===!1?!1:"function"==typeof i("canvas").getContext("2d").fillText}),Modernizr.addTest("video",function(){var e=i("video"),t=!1;try{t=!!e.canPlayType,t&&(t=new Boolean(t),t.ogg=e.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),t.h264=e.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),t.webm=e.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,""),t.vp9=e.canPlayType('video/webm; codecs="vp9"').replace(/^no$/,""),t.hls=e.canPlayType('application/x-mpegURL; codecs="avc1.42E01E"').replace(/^no$/,""))}catch(n){}return t}),Modernizr.addTest("webgl",function(){var t=i("canvas"),n="probablySupportsContext"in t?"probablySupportsContext":"supportsContext";return n in t?t[n]("webgl")||t[n]("experimental-webgl"):"WebGLRenderingContext"in e}),Modernizr.addTest("cssgradients",function(){for(var e,t="background-image:",n="gradient(linear,left top,right bottom,from(#9f9),to(white));",r="",o=0,a=_.length-1;a>o;o++)e=0===o?"to ":"",r+=t+_[o]+"linear-gradient("+e+"left top, #9f9, white);";Modernizr._config.usePrefixes&&(r+=t+"-webkit-"+n);var s=i("a"),c=s.style;return c.cssText=r,(""+c.backgroundImage).indexOf("gradient")>-1}),Modernizr.addTest("multiplebgs",function(){var e=i("a").style;return e.cssText="background:url(https://),url(https://),red url(https://)",/(url\s*\(.*?){3}/.test(e.background)}),Modernizr.addTest("opacity",function(){var e=i("a").style;return e.cssText=_.join("opacity:.55;"),/^0.55$/.test(e.opacity)}),Modernizr.addTest("rgba",function(){var e=i("a").style;return e.cssText="background-color:rgba(150,255,150,.5)",(""+e.backgroundColor).indexOf("rgba")>-1}),Modernizr.addTest("inlinesvg",function(){var e=i("div");return e.innerHTML="","http://www.w3.org/2000/svg"==("undefined"!=typeof SVGRect&&e.firstChild&&e.firstChild.namespaceURI)});var R=i("input"),A="autocomplete autofocus list placeholder max min multiple pattern required step".split(" "),M={};Modernizr.input=function(t){for(var n=0,r=t.length;r>n;n++)M[t[n]]=!!(t[n]in R);return M.list&&(M.list=!(!i("datalist")||!e.HTMLDataListElement)),M}(A);var $="search tel url email datetime date month week time datetime-local number range color".split(" "),B={};Modernizr.inputtypes=function(e){for(var r,o,a,i=e.length,s="1)",c=0;i>c;c++)R.setAttribute("type",r=e[c]),a="text"!==R.type&&"style"in R,a&&(R.value=s,R.style.cssText="position:absolute;visibility:hidden;",/^range$/.test(r)&&R.style.WebkitAppearance!==n?(k.appendChild(R),o=t.defaultView,a=o.getComputedStyle&&"textfield"!==o.getComputedStyle(R,null).WebkitAppearance&&0!==R.offsetHeight,k.removeChild(R)):/^(search|tel)$/.test(r)||(a=/^(url|email)$/.test(r)?R.checkValidity&&R.checkValidity()===!1:R.value!=s)),B[e[c]]=!!a;return B}($),Modernizr.addTest("hsla",function(){var e=i("a").style;return e.cssText="background-color:hsla(120,40%,100%,.5)",s(e.backgroundColor,"rgba")||s(e.backgroundColor,"hsla")});var j="CSS"in e&&"supports"in e.CSS,L="supportsCSS"in e;Modernizr.addTest("supports",j||L);var D={}.toString;Modernizr.addTest("svgclippaths",function(){return!!t.createElementNS&&/SVGClipPath/.test(D.call(t.createElementNS("http://www.w3.org/2000/svg","clipPath")))}),Modernizr.addTest("smil",function(){return!!t.createElementNS&&/SVGAnimate/.test(D.call(t.createElementNS("http://www.w3.org/2000/svg","animate")))});var F=function(){var t=e.matchMedia||e.msMatchMedia;return t?function(e){var n=t(e);return n&&n.matches||!1}:function(t){var n=!1;return l("@media "+t+" { #modernizr { position: absolute; } }",function(t){n="absolute"==(e.getComputedStyle?e.getComputedStyle(t,null):t.currentStyle).position}),n}}();S.mq=F;var I=S.testStyles=l,W=function(){var e=navigator.userAgent,t=e.match(/w(eb)?osbrowser/gi),n=e.match(/windows phone/gi)&&e.match(/iemobile\/([0-9])+/gi)&&parseFloat(RegExp.$1)>=9;return t||n}();W?Modernizr.addTest("fontface",!1):I('@font-face {font-family:"font";src:url("https://")}',function(e,n){var r=t.getElementById("smodernizr"),o=r.sheet||r.styleSheet,a=o?o.cssRules&&o.cssRules[0]?o.cssRules[0].cssText:o.cssText||"":"",i=/src/i.test(a)&&0===a.indexOf(n.split(" ")[0]);Modernizr.addTest("fontface",i)}),I('#modernizr{font:0/0 a}#modernizr:after{content:":)";visibility:hidden;font:7px/1 a}',function(e){Modernizr.addTest("generatedcontent",e.offsetHeight>=6)}),Modernizr.addTest("touchevents",function(){var n;if("ontouchstart"in e||e.DocumentTouch&&t instanceof DocumentTouch)n=!0;else{var r=["@media (",_.join("touch-enabled),("),"heartz",")","{#modernizr{top:9px;position:absolute}}"].join("");I(r,function(e){n=9===e.offsetTop})}return n});var U=S._config.usePrefixes?N.split(" "):[];S._cssomPrefixes=U;var V=function(t){var r,o=_.length,a=e.CSSRule;if("undefined"==typeof a)return n;if(!t)return!1;if(t=t.replace(/^@/,""),r=t.replace(/-/g,"_").toUpperCase()+"_RULE",r in a)return"@"+t;for(var i=0;o>i;i++){var s=_[i],c=s.toUpperCase()+"_"+r;if(c in a)return"@-"+s.toLowerCase()+"-"+t}return!1};S.atRule=V;var q;!function(){var e={}.hasOwnProperty;q=r(e,"undefined")||r(e.call,"undefined")?function(e,t){return t in e&&r(e.constructor.prototype[t],"undefined")}:function(t,n){return e.call(t,n)}}(),S._l={},S.on=function(e,t){this._l[e]||(this._l[e]=[]),this._l[e].push(t),Modernizr.hasOwnProperty(e)&&setTimeout(function(){Modernizr._trigger(e,Modernizr[e])},0)},S._trigger=function(e,t){if(this._l[e]){var n=this._l[e];setTimeout(function(){var e,r;for(e=0;e=1?"floor":"ceil"](delta/lowestDelta);deltaX=Math[deltaX>=1?"fl event.deltaX=deltaX;event.deltaY=deltaY;event.deltaFactor=lowestDelta;event.deltaMode=0;args.unshift(event,delta,deltaX,deltaY);if(nullLowestDeltaTimeout){window.clearTimeout(nullLowestDeltaTimeout);} nullLowestDeltaTimeout=window.setTimeout(nullLowestDelta,200);return($.event.dispatch||$.event.handle).apply(this,args);} function nullLowestDelta(){lowestDelta=null;} -function shouldAdjustOldDeltas(orgEvent,absDelta){return special.settings.adjustOldDeltas&&orgEvent.type==="mousewheel"&&absDelta%120===0;}});!function($,window,pluginName,undefined){var containerDefaults={drag:true,drop:true,exclude:"",nested:true,vertical:true},groupDefaults={afterMove:function($placeholder,container,$closestItemOrContainer){},containerPath:"",containerSelector:"ol, ul",distance:0,delay:0,handle:"",itemPath:"",itemSelector:"li",bodyClass:"dragging",draggedClass:"dragged",isValidTarget:function($item,container){return true},onCancel:function($item,container,_super,event){},onDrag:function($item,position,_super,event){$item.css(position)},onDragStart:function($item,container,_super,event){$item.css({height:$item.outerHeight(),width:$item.outerWidth()}) +function shouldAdjustOldDeltas(orgEvent,absDelta){return special.settings.adjustOldDeltas&&orgEvent.type==="mousewheel"&&absDelta%120===0;}});!function($,window,pluginName,undefined){var containerDefaults={drag:true,drop:true,exclude:"",nested:true,vertical:true},groupDefaults={afterMove:function($placeholder,container,$closestItemOrContainer){},containerPath:"",containerSelector:"ol, ul",distance:0,delay:0,handle:"",itemPath:"",itemSelector:"li",bodyClass:"dragging",draggedClass:"dragged",isValidTarget:function($item,container){return true},onCancel:function($item,container,_super,event){},onDrag:function($item,position,_super,event){$item.css(position) +event.preventDefault()},onDragStart:function($item,container,_super,event){$item.css({height:$item.outerHeight(),width:$item.outerWidth()}) $item.addClass(container.group.options.draggedClass) $("body").addClass(container.group.options.bodyClass)},onDrop:function($item,container,_super,event){$item.removeClass(container.group.options.draggedClass).removeAttr("style") -$("body").removeClass(container.group.options.bodyClass)},onMousedown:function($item,_super,event){if(!event.target.nodeName.match(/^(input|select|textarea)$/i)){event.preventDefault() +$("body").removeClass(container.group.options.bodyClass)},onMousedown:function($item,_super,event){if(!event.target.nodeName.match(/^(input|select|textarea)$/i)){if(event.type.match(/^mouse/))event.preventDefault() return true}},placeholderClass:"placeholder",placeholder:'
  • ',pullPlaceholder:true,serialize:function($parent,$children,parentIsContainer){var result=$.extend({},$parent.data()) -if(parentIsContainer) -return[$children] +if(parentIsContainer){return[$children]} else if($children[0]){result.children=$children} delete result.subContainers delete result.sortable @@ -1757,8 +1757,8 @@ this.lastRelativePointer=this.relativePointer this.relativePointer=relativePointer} this.lastPointer=this.pointer this.pointer=pointer},distanceMet:function(e){var currentPointer=this.getPointer(e) -return(Math.max(Math.abs(this.pointer.left-currentPointer.left),Math.abs(this.pointer.top-currentPointer.top))>=this.options.distance)},getPointer:function(e){var o=e.originalEvent||e.originalEvent.touches&&e.originalEvent.touches[0] -return{left:e.pageX||o.pageX,top:e.pageY||o.pageY}},setupDelayTimer:function(){var that=this +return(Math.max(Math.abs(this.pointer.left-currentPointer.left),Math.abs(this.pointer.top-currentPointer.top))>=this.options.distance)},getPointer:function(e){var o=e.originalEvent,t=(e.originalEvent.touches&&e.originalEvent.touches[0])||{} +return{left:e.pageX||o.pageX||t.pageX,top:e.pageY||o.pageY||t.pageY}},setupDelayTimer:function(){var that=this this.delayMet=!this.options.delay if(!this.delayMet){clearTimeout(this._mouseDelayTimer);this._mouseDelayTimer=setTimeout(function(){that.delayMet=true},this.options.delay)}},scroll:function(e){this.clearDimensions() this.clearOffsetParent()},toggleListeners:function(method){var that=this,events=['drag','drop','scroll'] diff --git a/modules/system/assets/ui/vendor/sortable/jquery-sortable.js b/modules/system/assets/ui/vendor/sortable/jquery-sortable.js index 6cbd80634d..8227b4c20f 100644 --- a/modules/system/assets/ui/vendor/sortable/jquery-sortable.js +++ b/modules/system/assets/ui/vendor/sortable/jquery-sortable.js @@ -85,6 +85,7 @@ // The Placeholder has not been moved yet. onDrag: function ($item, position, _super, event) { $item.css(position) + event.preventDefault() }, // Called after the drag has been started, // that is the mouse button is being held down and @@ -108,7 +109,7 @@ // Ignore if element clicked is input, select or textarea onMousedown: function ($item, _super, event) { if (!event.target.nodeName.match(/^(input|select|textarea)$/i)) { - event.preventDefault() + if (event.type.match(/^mouse/)) event.preventDefault() return true } }, @@ -126,8 +127,9 @@ serialize: function ($parent, $children, parentIsContainer) { var result = $.extend({}, $parent.data()) - if(parentIsContainer) + if (parentIsContainer) { return [$children] + } else if ($children[0]){ result.children = $children } @@ -253,7 +255,7 @@ this.item = closestItem; this.itemContainer = itemContainer; if (this.item.is(this.options.exclude) || !this.options.onMousedown(this.item, groupDefaults.onMousedown, e)) { - return; + return; } this.setPointer(e); this.toggleListeners('on'); @@ -400,10 +402,11 @@ ) >= this.options.distance) }, getPointer: function(e) { - var o = e.originalEvent || e.originalEvent.touches && e.originalEvent.touches[0] + var o = e.originalEvent, + t = (e.originalEvent.touches && e.originalEvent.touches[0]) || {} return { - left: e.pageX || o.pageX, - top: e.pageY || o.pageY + left: e.pageX || o.pageX || t.pageX, + top: e.pageY || o.pageY || t.pageY } }, setupDelayTimer: function () { @@ -689,4 +692,4 @@ }); }; -}(jQuery, window, 'jqSortable'); \ No newline at end of file +}(jQuery, window, 'jqSortable'); From 0d263cd33a0ddc491cf7b243e666f2a1aa06bcbc Mon Sep 17 00:00:00 2001 From: Ben Thomson Date: Thu, 28 Nov 2019 22:23:28 +0800 Subject: [PATCH 120/157] Number range filter improvements (#4789) - Allow minimum or maximum to be unspecified, meaning you want everything up to maximum, or everything above minimum. - Allow for zero values to work - Tweak display of infinite values Fixes #3982. --- modules/backend/widgets/Filter.php | 20 +++++++++---------- modules/system/assets/ui/js/filter.numbers.js | 2 +- modules/system/assets/ui/storm-min.js | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/modules/backend/widgets/Filter.php b/modules/backend/widgets/Filter.php index ddb8b68925..a508007fed 100644 --- a/modules/backend/widgets/Filter.php +++ b/modules/backend/widgets/Filter.php @@ -145,18 +145,19 @@ public function renderScopeElement($scope) break; case 'numberrange': - if ($scope->value && is_array($scope->value) && count($scope->value) === 2 && - $scope->value[0] && - $scope->value[1] + if ( + $scope->value + && (is_array($scope->value) && count($scope->value) === 2) + && (isset($scope->value[0]) || isset($scope->value[1])) ) { $min = $scope->value[0]; $max = $scope->value[1]; - $params['minStr'] = $min ?: ''; - $params['min'] = $min ?: null; + $params['minStr'] = $min ?? '∞'; + $params['min'] = $min ?? null; - $params['maxStr'] = $max ?: '∞'; - $params['max'] = $max ?: null; + $params['maxStr'] = $max ?? '∞'; + $params['max'] = $max ?? null; } break; @@ -790,7 +791,7 @@ public function applyScopeToQuery($scope, $query) if (is_array($scope->value) && count($scope->value) > 1) { list($min, $max) = array_values($scope->value); - if ($min && $max) { + if (isset($min) || isset($max)) { /* * Condition * @@ -1049,8 +1050,7 @@ protected function numbersFromAjax($ajaxNumbers) if (preg_match($numberRegex, $number)) { $numbers[] = $number; } else { - $numbers = []; - break; + $numbers[] = null; } } } diff --git a/modules/system/assets/ui/js/filter.numbers.js b/modules/system/assets/ui/js/filter.numbers.js index 1a2cb071f3..d0c8cef0fa 100644 --- a/modules/system/assets/ui/js/filter.numbers.js +++ b/modules/system/assets/ui/js/filter.numbers.js @@ -257,7 +257,7 @@ numbers[1] = numbers[1] && numbers[1].match(numberRegex) ? numbers[1] : null if(numbers[0] || numbers[1]) { - var min = numbers[0] ? numbers[0] : '', + var min = numbers[0] ? numbers[0] : '∞', max = numbers[1] ? numbers[1] : '∞' $setting.text(min + ' → ' + max) diff --git a/modules/system/assets/ui/storm-min.js b/modules/system/assets/ui/storm-min.js index 7576ace785..f4c8efa10e 100644 --- a/modules/system/assets/ui/storm-min.js +++ b/modules/system/assets/ui/storm-min.js @@ -3485,7 +3485,7 @@ numberinput.value=''!==defaultValue?defaultValue:'';})} FilterWidget.prototype.updateScopeNumberSetting=function($scope,numbers){var $setting=$scope.find('.filter-setting'),numberRegex=/\d*/,reset=false if(numbers&&numbers.length){numbers[0]=numbers[0]&&numbers[0].match(numberRegex)?numbers[0]:null if(numbers.length>1){numbers[1]=numbers[1]&&numbers[1].match(numberRegex)?numbers[1]:null -if(numbers[0]||numbers[1]){var min=numbers[0]?numbers[0]:'',max=numbers[1]?numbers[1]:'∞' +if(numbers[0]||numbers[1]){var min=numbers[0]?numbers[0]:'∞',max=numbers[1]?numbers[1]:'∞' $setting.text(min+' → '+max)}else{reset=true}} else if(numbers[0]){$setting.text(numbers[0])}else{reset=true}} else{reset=true} From 0b185537bf65266632fa5d8f7f18284c1598dfa8 Mon Sep 17 00:00:00 2001 From: Ben Thomson Date: Thu, 28 Nov 2019 22:53:40 +0800 Subject: [PATCH 121/157] Drop PHP 7.4 testing for now Will bring it back with the L6 upgrade. --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 072b795dac..b6e29f9a4a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,7 +13,7 @@ jobs: strategy: max-parallel: 6 matrix: - phpVersions: ['7.1', '7.2', '7.3', '7.4'] + phpVersions: ['7.1', '7.2', '7.3'] fail-fast: false name: PHP ${{ matrix.phpVersions }} steps: From d41193685f250500c4cb5a0a0e1418b8a4388fd3 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Thu, 28 Nov 2019 10:32:34 -0600 Subject: [PATCH 122/157] Revert #4567, fixes #4648. If including the asset extension is important, this can be done by listening to the `system.assets.beforeAddAsset(&$type, &$path, &$attributes)` event introduced in Build 460. --- modules/system/classes/CombineAssets.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/system/classes/CombineAssets.php b/modules/system/classes/CombineAssets.php index 87a9d1d8fa..6da6e195c7 100644 --- a/modules/system/classes/CombineAssets.php +++ b/modules/system/classes/CombineAssets.php @@ -400,7 +400,7 @@ protected function prepareRequest(array $assets, $localPath = null) $this->putCache($cacheKey, $cacheInfo); } - return $this->getCombinedUrl($cacheInfo['version'] . '.' . $extension); + return $this->getCombinedUrl($cacheInfo['version']); } /** From be7b9b03f3d25fdbadd2f26c83de6b1612b73239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20K=C3=BCndig?= Date: Fri, 29 Nov 2019 08:26:37 +0100 Subject: [PATCH 123/157] Only put sortOptions to the session if the List query succeeded --- modules/backend/widgets/Lists.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/modules/backend/widgets/Lists.php b/modules/backend/widgets/Lists.php index c4bfd4f43f..862e96d400 100644 --- a/modules/backend/widgets/Lists.php +++ b/modules/backend/widgets/Lists.php @@ -1496,14 +1496,20 @@ public function onSort() $this->sortColumn = $sortOptions['column'] = $column; - $this->putSession('sort', $sortOptions); - /* * Persist the page number */ $this->currentPageNumber = post('page'); - return $this->onRefresh(); + /* + * Try to refresh the list with the new sortOptions. Put the + * new sortOptions in to the session if the query succeeded. + */ + $result = $this->onRefresh(); + + $this->putSession('sort', $sortOptions); + + return $result; } } From c8cc12686a01b202685e238d6ba7064ed45f3738 Mon Sep 17 00:00:00 2001 From: Ben Thomson Date: Sat, 30 Nov 2019 00:09:49 +0800 Subject: [PATCH 124/157] Trigger "change" event when time picker is changed This allows dependent fields (ie. dependsOn) to trigger correctly when a time field, or the time part of a datetime field, is changed. Fixes #4268 --- modules/system/assets/ui/js/datepicker.js | 9 +++++++-- modules/system/assets/ui/storm-min.js | 3 ++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/modules/system/assets/ui/js/datepicker.js b/modules/system/assets/ui/js/datepicker.js index f6a46bb126..d840f01de3 100644 --- a/modules/system/assets/ui/js/datepicker.js +++ b/modules/system/assets/ui/js/datepicker.js @@ -190,8 +190,8 @@ autoclose: 'true', placement: 'auto', align: 'right', - twelvehour: this.isTimeTwelveHour() - // afterDone: this.proxy(this.onSelectTimePicker) + twelvehour: this.isTimeTwelveHour(), + afterDone: this.proxy(this.onChangeTimePicker) }) this.$timePicker.val(this.getDataLockerValue(this.getTimeFormat())) @@ -213,6 +213,11 @@ this.$dataLocker.val(lockerValue) } + DatePicker.prototype.onChangeTimePicker = function() { + // Trigger a change event when the time is changed, to allow dependent fields to refresh + this.$timePicker.trigger('change') + } + // Returns in user preference timezone DatePicker.prototype.getTimePickerValue = function() { var value = this.$timePicker.val() diff --git a/modules/system/assets/ui/storm-min.js b/modules/system/assets/ui/storm-min.js index f4c8efa10e..b0634059f3 100644 --- a/modules/system/assets/ui/storm-min.js +++ b/modules/system/assets/ui/storm-min.js @@ -2964,7 +2964,7 @@ DatePicker.prototype.getDateFormat=function(){var format='YYYY-MM-DD' if(this.options.format){format=this.options.format} else if(this.locale){format=moment().locale(this.locale).localeData().longDateFormat('l')} return format} -DatePicker.prototype.initTimePicker=function(){this.$timePicker.clockpicker({autoclose:'true',placement:'auto',align:'right',twelvehour:this.isTimeTwelveHour()}) +DatePicker.prototype.initTimePicker=function(){this.$timePicker.clockpicker({autoclose:'true',placement:'auto',align:'right',twelvehour:this.isTimeTwelveHour(),afterDone:this.proxy(this.onChangeTimePicker)}) this.$timePicker.val(this.getDataLockerValue(this.getTimeFormat()))} DatePicker.prototype.onSelectTimePicker=function(){var pickerValue=this.$timePicker.val() var timeValue=moment(pickerValue,this.getTimeFormat()).format(this.dbTimeFormat) @@ -2972,6 +2972,7 @@ var dateValue=this.getDatePickerValue() var momentObj=moment.tz(dateValue+' '+timeValue,this.dbDateTimeFormat,this.timezone).tz(this.appTimezone) var lockerValue=momentObj.format(this.dbDateTimeFormat) this.$dataLocker.val(lockerValue)} +DatePicker.prototype.onChangeTimePicker=function(){this.$timePicker.trigger('change')} DatePicker.prototype.getTimePickerValue=function(){var value=this.$timePicker.val() if(!this.hasTime||!value){return moment.tz(this.appTimezone).tz(this.timezone).format(this.dbTimeFormat)} return moment(value,this.getTimeFormat()).format(this.dbTimeFormat)} From b2be8c93726e45065cda79018af24e2b326bd2fc Mon Sep 17 00:00:00 2001 From: Ben Thomson Date: Mon, 2 Dec 2019 09:27:25 +0800 Subject: [PATCH 125/157] Force ordering when list widget column is sorted When ordering is applied externally, ie. by a relation config, the orderBy call in the List widget simply adds an additional field to the ordering clauses, which prevents lists in these scenarios from being re-ordered correctly. This changes the order clause so that the ordering is reset and only the specified column is ordered when the user sorts a column. Developers can continue to use the `extendQuery` event to do specialised custom ordering if required. Fixes #4439. --- modules/backend/widgets/Lists.php | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/backend/widgets/Lists.php b/modules/backend/widgets/Lists.php index 862e96d400..f1946d747a 100644 --- a/modules/backend/widgets/Lists.php +++ b/modules/backend/widgets/Lists.php @@ -532,6 +532,7 @@ public function prepareQuery() $sortColumn = $column->relation . '_count'; } + $query->getQuery()->orders = []; $query->orderBy($sortColumn, $this->sortDirection); } From 9bc9e9e03c46e8fa71ddce0d0ee13d16a7907f9e Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Mon, 2 Dec 2019 17:27:43 +1100 Subject: [PATCH 126/157] Fix for strict SQL languages (Pgsql) When the value is null [id >= ''] an error is thrown, not being an integer, while [id >= null] will return nil results, curiously. Here we emulate infinity by using a large-ish number instead of null. In future if this becomes a problem we may need to resort to multiple condition definitions as a more verbose solution, for example: - For when both are set (conditions: id >= ':min' and id <= ':max') - For when min is set (conditionsMin: id >= ':min') - For when max is set (conditionsMax: id >= ':max') --- modules/backend/widgets/Filter.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/backend/widgets/Filter.php b/modules/backend/widgets/Filter.php index a508007fed..3562cd49d6 100644 --- a/modules/backend/widgets/Filter.php +++ b/modules/backend/widgets/Filter.php @@ -794,12 +794,11 @@ public function applyScopeToQuery($scope, $query) if (isset($min) || isset($max)) { /* * Condition - * */ if ($scopeConditions = $scope->conditions) { $query->whereRaw(DbDongle::parse(strtr($scopeConditions, [ - ':min' => $min, - ':max' => $max + ':min' => $min === null ? -999999999 : $min, + ':max' => $max === null ? 999999999 : $max ]))); } /* From 5e0267656685e6e26c2dcfb771d75f828a4fcd9c Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Wed, 4 Dec 2019 08:25:44 +1100 Subject: [PATCH 127/157] Tweak chart markup to not depend on an external class This fixes the rendering of the example markup. The line chart has no styles but just needs to know the display height --- modules/system/assets/ui/docs/chart.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/system/assets/ui/docs/chart.md b/modules/system/assets/ui/docs/chart.md index cd576fe6b2..695da93681 100644 --- a/modules/system/assets/ui/docs/chart.md +++ b/modules/system/assets/ui/docs/chart.md @@ -27,10 +27,10 @@ The next example shows a line chart markup. Data sets are defined with the SPAN
    - From f7876800be8cd4162f0d558ec7eb5dea8e2fb11b Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Wed, 4 Dec 2019 18:30:32 +1100 Subject: [PATCH 128/157] Make fake-infinity precise to 4 bytes --- modules/backend/widgets/Filter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/backend/widgets/Filter.php b/modules/backend/widgets/Filter.php index 3562cd49d6..48153bf509 100644 --- a/modules/backend/widgets/Filter.php +++ b/modules/backend/widgets/Filter.php @@ -797,8 +797,8 @@ public function applyScopeToQuery($scope, $query) */ if ($scopeConditions = $scope->conditions) { $query->whereRaw(DbDongle::parse(strtr($scopeConditions, [ - ':min' => $min === null ? -999999999 : $min, - ':max' => $max === null ? 999999999 : $max + ':min' => $min === null ? -2147483647 : $min, + ':max' => $max === null ? 2147483647 : $max ]))); } /* From 2d8a0c8199e28a60c3457aa8465383399cfa9816 Mon Sep 17 00:00:00 2001 From: empower-josh <45080572+empower-josh@users.noreply.github.com> Date: Wed, 4 Dec 2019 01:29:24 -0700 Subject: [PATCH 129/157] Add public methods to access Lists widget's sort direction & column (#4746) Credit to @empower-josh. --- modules/backend/widgets/Lists.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/modules/backend/widgets/Lists.php b/modules/backend/widgets/Lists.php index f1946d747a..59fc311944 100644 --- a/modules/backend/widgets/Lists.php +++ b/modules/backend/widgets/Lists.php @@ -1517,7 +1517,7 @@ public function onSort() /** * Returns the current sorting column, saved in a session or cached. */ - protected function getSortColumn() + public function getSortColumn() { if (!$this->isSortable()) { return false; @@ -1564,6 +1564,14 @@ protected function getSortColumn() return $this->sortColumn; } + /* + * Returns the current sort direction or default of 'asc' + */ + public function getSortDirection() + { + return $this->sortDirection ?? 'asc'; + } + /** * Returns true if the column can be sorted. */ From 79403cb997c2474a5199c4249df8a7bb0100de21 Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Wed, 4 Dec 2019 02:36:51 -0600 Subject: [PATCH 130/157] Narrow the scope of when Lists orderBy conditions are reset. Credit to @bennothommo & @daftspunk Replaces: https://github.com/octobercms/october/commit/9f8d8ec9fabad06e0eb4b222611910e608729074. Refs: #4439 --- modules/backend/behaviors/RelationController.php | 5 ++++- modules/backend/widgets/Lists.php | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/backend/behaviors/RelationController.php b/modules/backend/behaviors/RelationController.php index 542e4c7cf5..2306b5ffbc 100644 --- a/modules/backend/behaviors/RelationController.php +++ b/modules/backend/behaviors/RelationController.php @@ -706,8 +706,11 @@ protected function makeViewWidget() }); } else { - $widget->bindEvent('list.extendQueryBefore', function ($query) { + $widget->bindEvent('list.extendQueryBefore', function ($query) use ($widget) { $this->relationObject->addDefinedConstraintsToQuery($query); + if ($widget->getSortColumn()) { + $query->getQuery()->orders = []; + } }); } diff --git a/modules/backend/widgets/Lists.php b/modules/backend/widgets/Lists.php index 59fc311944..cd2b96723e 100644 --- a/modules/backend/widgets/Lists.php +++ b/modules/backend/widgets/Lists.php @@ -532,7 +532,6 @@ public function prepareQuery() $sortColumn = $column->relation . '_count'; } - $query->getQuery()->orders = []; $query->orderBy($sortColumn, $this->sortDirection); } From bb62f012b207d38cee004c41cf6bf3f7f1b57c89 Mon Sep 17 00:00:00 2001 From: Philipp Fehr Date: Wed, 4 Dec 2019 17:14:19 +0100 Subject: [PATCH 131/157] Fix race condition when clearing recordfinder value (#4802) Credit to @TheFehr. Fixes #4800. --- .../backend/formwidgets/recordfinder/partials/_recordfinder.htm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/backend/formwidgets/recordfinder/partials/_recordfinder.htm b/modules/backend/formwidgets/recordfinder/partials/_recordfinder.htm index 65878029e8..a347114ba8 100644 --- a/modules/backend/formwidgets/recordfinder/partials/_recordfinder.htm +++ b/modules/backend/formwidgets/recordfinder/partials/_recordfinder.htm @@ -28,7 +28,7 @@ class="btn btn-default clear-record" data-request="getEventHandler('onClearRecord') ?>" data-request-confirm="" - data-request-success="$('#getId() ?>').trigger('change')" + data-request-success="var $locker = $('#getId() ?>'); $locker.val(''); $locker.trigger('change')" aria-label="Remove"> From 50107e15328f253fd2b04e04180e4072094c37a0 Mon Sep 17 00:00:00 2001 From: Larry Barker Date: Thu, 5 Dec 2019 02:44:04 -0600 Subject: [PATCH 132/157] Support additional file name and path characters in media manager (#4564) * Support additional file name and path characters in media manager When working with abstract file names that may contain additional characters, such as quotes or ampersands, the media manager would throw an error. This PR adds two additional characters to the character whitelist. * Add unicode filename to tests --- modules/system/classes/MediaLibrary.php | 2 ++ tests/unit/system/classes/MediaLibraryTest.php | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/modules/system/classes/MediaLibrary.php b/modules/system/classes/MediaLibrary.php index 6458257508..93b6fe58f8 100644 --- a/modules/system/classes/MediaLibrary.php +++ b/modules/system/classes/MediaLibrary.php @@ -486,6 +486,8 @@ public static function validatePath($path, $normalizeOnly = false) preg_quote(']', '/'), preg_quote(',', '/'), preg_quote('=', '/'), + preg_quote("'", '/'), + preg_quote('&', '/'), ]; if (!preg_match('/^[' . implode('', $regexWhitelist) . ']+$/iu', $path)) { diff --git a/tests/unit/system/classes/MediaLibraryTest.php b/tests/unit/system/classes/MediaLibraryTest.php index 55c0275440..24bab1567e 100644 --- a/tests/unit/system/classes/MediaLibraryTest.php +++ b/tests/unit/system/classes/MediaLibraryTest.php @@ -37,6 +37,11 @@ public function validPathsProvider() ['one(two)[].ext'], ['one=(two)[].ext'], ['one_(two)[].ext'], + /* + Example of a unicode-based filename with a single quote + @see: https://github.com/octobercms/october/pull/4564 + */ + ['BG中国通讯期刊(Blend\'r)创刊号.pdf'], ]; } From 1552c709070bfc6a5ea0d66e6b2978664e1d8cd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20K=C3=BCndig?= Date: Sat, 7 Dec 2019 01:33:06 +0100 Subject: [PATCH 133/157] Explicitly pass focused item along as it is already known (#4807) If the DataTable widget is loaded in a Popup, the .focus() call does not seem to focus the target element correctly, which leads to the problem, that the updateCellFromFocusedItem method fails to find the focused item. This commit passes the target item along since it is already known. --- modules/backend/widgets/table/assets/js/build-min.js | 5 +++-- .../widgets/table/assets/js/table.processor.dropdown.js | 8 +++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/modules/backend/widgets/table/assets/js/build-min.js b/modules/backend/widgets/table/assets/js/build-min.js index 7bac16e129..8c8a8637b7 100644 --- a/modules/backend/widgets/table/assets/js/build-min.js +++ b/modules/backend/widgets/table/assets/js/build-min.js @@ -871,7 +871,8 @@ return cachingKey} DropdownProcessor.prototype.getAbsolutePosition=function(element){var top=document.body.scrollTop,left=0 do{top+=element.offsetTop||0;top-=element.scrollTop||0;left+=element.offsetLeft||0;element=element.offsetParent;}while(element) return{top:top,left:left}} -DropdownProcessor.prototype.updateCellFromFocusedItem=function(){var focusedItem=this.findFocusedItem();this.setSelectedItem(focusedItem);} +DropdownProcessor.prototype.updateCellFromFocusedItem=function(focusedItem){if(!focusedItem){focusedItem=this.findFocusedItem();} +this.setSelectedItem(focusedItem);} DropdownProcessor.prototype.findSelectedItem=function(){if(this.itemListElement) return this.itemListElement.querySelector('ul li.selected') return null} @@ -883,7 +884,7 @@ DropdownProcessor.prototype.findFocusedItem=function(){if(this.itemListElement) return this.itemListElement.querySelector('ul li:focus') return null} DropdownProcessor.prototype.onItemClick=function(ev){var target=this.tableObj.getEventTarget(ev) -if(target.tagName=='LI'){target.focus();this.updateCellFromFocusedItem() +if(target.tagName=='LI'){target.focus();this.updateCellFromFocusedItem(target) this.hideDropdown()}} DropdownProcessor.prototype.onItemKeyDown=function(ev){if(!this.itemListElement) return diff --git a/modules/backend/widgets/table/assets/js/table.processor.dropdown.js b/modules/backend/widgets/table/assets/js/table.processor.dropdown.js index 466c714757..3155b81498 100644 --- a/modules/backend/widgets/table/assets/js/table.processor.dropdown.js +++ b/modules/backend/widgets/table/assets/js/table.processor.dropdown.js @@ -270,8 +270,10 @@ } } - DropdownProcessor.prototype.updateCellFromFocusedItem = function() { - var focusedItem = this.findFocusedItem(); + DropdownProcessor.prototype.updateCellFromFocusedItem = function(focusedItem) { + if (!focusedItem) { + focusedItem = this.findFocusedItem(); + } this.setSelectedItem(focusedItem); } @@ -309,7 +311,7 @@ if (target.tagName == 'LI') { target.focus(); - this.updateCellFromFocusedItem() + this.updateCellFromFocusedItem(target) this.hideDropdown() } } From d164392c38213bc1601e0d7fb22fe396a5c6cb5b Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Sat, 7 Dec 2019 11:37:06 +1100 Subject: [PATCH 134/157] Minor continuity change Let's save this for L6 upgrade. Although PHP 7 partially support this, we should revisit once the PHP version is bumped + better support for it --- modules/backend/traits/PreferenceMaker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/backend/traits/PreferenceMaker.php b/modules/backend/traits/PreferenceMaker.php index 92ce005361..728329059c 100644 --- a/modules/backend/traits/PreferenceMaker.php +++ b/modules/backend/traits/PreferenceMaker.php @@ -54,7 +54,7 @@ public function getUserPreference(string $key = null, $default = null) * * @return array */ - public function getUserPreferences(): array + public function getUserPreferences() { if (isset(self::$preferenceCache[$this->getPreferenceKey()])) { return self::$preferenceCache[$this->getPreferenceKey()]; @@ -112,7 +112,7 @@ public function clearUserPreferences() * * @return string */ - protected function getPreferenceKey(): string + protected function getPreferenceKey() { $controller = (property_exists($this, 'controller') && $this->controller) ? $this->controller From 789254708c14e59db9e4d192f8651b076b8319c4 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Sun, 8 Dec 2019 10:27:59 +1100 Subject: [PATCH 135/157] Prevents erratic rendering issues This occurs due to a race condition in the rendering where the scrollbars enable and disable over and over because of a slow height calculation. Giving any height number appears to close the loop by never letting the height resolve to 0 Refs #4632 --- .../backend/widgets/mediamanager/assets/css/mediamanager.css | 2 +- .../widgets/mediamanager/assets/less/mediamanager.less | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/backend/widgets/mediamanager/assets/css/mediamanager.css b/modules/backend/widgets/mediamanager/assets/css/mediamanager.css index 74e0a857ab..c98ed5a1fd 100644 --- a/modules/backend/widgets/mediamanager/assets/css/mediamanager.css +++ b/modules/backend/widgets/mediamanager/assets/css/mediamanager.css @@ -73,7 +73,7 @@ div[data-control="media-manager"] .list-container p.no-data {padding:0 20px 20px div[data-control="media-manager"] .list-container li.no-data {padding-top:20px;display:block !important;width:100% !important;border:none !important;background:transparent !important;cursor:default !important} div[data-control="media-manager"] .list-container table.table.data tbody tr:not(.no-data):active td {background:#4ea5e0 !important} div[data-control="media-manager"] [data-control="item-list"] {position:relative;display:table-cell} -div[data-control="media-manager"] .control-scrollpad {position:absolute;left:0;top:0} +div[data-control="media-manager"] .control-scrollpad {position:absolute;left:0;top:0;min-height:300px} div[data-control="media-manager"] .scroll-wrapper {position:relative} div[data-control="media-manager"] table.table {table-layout:fixed;margin-bottom:0;white-space:nowrap} div[data-control="media-manager"] table.table div.no-wrap-text {overflow:hidden;text-overflow:ellipsis} diff --git a/modules/backend/widgets/mediamanager/assets/less/mediamanager.less b/modules/backend/widgets/mediamanager/assets/less/mediamanager.less index 9ff16d3939..285215d97b 100644 --- a/modules/backend/widgets/mediamanager/assets/less/mediamanager.less +++ b/modules/backend/widgets/mediamanager/assets/less/mediamanager.less @@ -395,6 +395,10 @@ div[data-control="media-manager"] { position: absolute; left: 0; top: 0; + + // Prevents erratic rendering issues when the height is + // sometimes calculated as 0 then repeatedly redrawn + min-height: 300px; } .scroll-wrapper { From ba62bd860fee7838ab5bfeab4a9a166bcc4597fd Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Mon, 9 Dec 2019 20:30:48 +1100 Subject: [PATCH 136/157] Bump min requirements to 7.0.8 This fixes PHP 7.4 support by pulling in Symfony packages at v3.4.36 --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index e08f1cdde6..0a77776053 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,7 @@ "source": "https://github.com/octobercms/october" }, "require": { - "php": ">=7.0", + "php": ">=7.0.8", "ext-mbstring": "*", "ext-openssl": "*", "october/rain": "~1.0", @@ -71,7 +71,7 @@ "config": { "preferred-install": "dist", "platform": { - "php": "7.0" + "php": "7.0.8" } }, "minimum-stability": "dev", From 6c23f1a77ecf87535a3f3717d467d4df3251a00b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20K=C3=BCndig?= Date: Mon, 9 Dec 2019 10:45:26 +0100 Subject: [PATCH 137/157] Added lazy loading for backend form tabs (#4658) * Added lazy loading for backend form tabs --- modules/backend/classes/FormTabs.php | 9 +++++ modules/backend/widgets/Form.php | 31 ++++++++++++++++- .../widgets/form/assets/js/october.form.js | 31 ++++++++++++++++- .../widgets/form/partials/_form_tabs.htm | 25 ++++++++++---- .../widgets/form/partials/_form_tabs_lazy.htm | 33 +++++++++++++++++++ 5 files changed, 120 insertions(+), 9 deletions(-) create mode 100644 modules/backend/widgets/form/partials/_form_tabs_lazy.htm diff --git a/modules/backend/classes/FormTabs.php b/modules/backend/classes/FormTabs.php index 709a0306ec..74ccae2f22 100644 --- a/modules/backend/classes/FormTabs.php +++ b/modules/backend/classes/FormTabs.php @@ -27,6 +27,11 @@ class FormTabs implements IteratorAggregate, ArrayAccess */ public $fields = []; + /** + * @var array Names of tabs to lazy load. + */ + public $lazy = []; + /** * @var string Default tab label to use when none is specified. */ @@ -106,6 +111,10 @@ protected function evalConfig($config) if (array_key_exists('paneCssClass', $config)) { $this->paneCssClass = $config['paneCssClass']; } + + if (array_key_exists('lazy', $config)) { + $this->lazy = $config['lazy']; + } } /** diff --git a/modules/backend/widgets/Form.php b/modules/backend/widgets/Form.php index ce42ad24b4..efda2e017b 100644 --- a/modules/backend/widgets/Form.php +++ b/modules/backend/widgets/Form.php @@ -456,6 +456,35 @@ public function onRefresh() return $result; } + /** + * Renders all fields of a tab in the target tab-pane. + * + * @return array + */ + public function onLazyLoadTab() + { + $target = post('target'); + $tabName = post('name'); + + $fields = array_get(optional($this->getTab('primary'))->fields, $tabName); + + return [ + $target => $this->makePartial('form_fields', ['fields' => $fields]), + ]; + } + + /** + * Helper method to convert a field name to a valid ID attribute. + * + * @param $input + * + * @return string + */ + public function nameToId($input) + { + return HtmlHelper::nameToId($input); + } + /** * Creates a flat array of form fields from the configuration. * Also slots fields in to their respective tabs. @@ -935,7 +964,7 @@ protected function makeFormFieldWidget($field) } $widgetConfig = $this->makeConfig($field->config); - $widgetConfig->alias = $this->alias . studly_case(HtmlHelper::nameToId($field->fieldName)); + $widgetConfig->alias = $this->alias . studly_case($this->nameToId($field->fieldName)); $widgetConfig->sessionKey = $this->getSessionKey(); $widgetConfig->previewMode = $this->previewMode; $widgetConfig->model = $this->model; diff --git a/modules/backend/widgets/form/assets/js/october.form.js b/modules/backend/widgets/form/assets/js/october.form.js index 2a95c5aaea..7b82f57596 100644 --- a/modules/backend/widgets/form/assets/js/october.form.js +++ b/modules/backend/widgets/form/assets/js/october.form.js @@ -34,6 +34,7 @@ this.bindDependants() this.bindCheckboxlist() this.toggleEmptyTabs() + this.bindLazyTabs() this.bindCollapsibleSections() this.$el.on('oc.triggerOn.afterUpdate', this.proxy(this.toggleEmptyTabs)) @@ -161,6 +162,34 @@ }) } + /* + * Render tab form fields once a lazy tab is selected. + */ + FormWidget.prototype.bindLazyTabs = function() { + this.$el.on('click', '.tab-lazy [data-toggle="tab"]', function() { + var $el = $(this) + $.request('form::onLazyLoadTab', { + data: { + target: $el.data('target'), + name: $el.data('tab-name'), + }, + success: function(data) { + this.success(data) + $el.parent().removeClass('tab-lazy') + // Trigger all input presets to populate new fields. + setTimeout(function() { + $('[data-input-preset]').each(function() { + var preset = $(this).data('oc.inputPreset') + if (preset && preset.$src) { + preset.$src.trigger('input') + } + }) + }, 0) + } + }) + }) + } + /* * Hides tabs that have no content, it is possible this can be * called multiple times in a single cycle due to input.trigger. @@ -184,7 +213,7 @@ /* * Check each tab pane for form field groups */ - $('.tab-pane', tabControl).each(function() { + $('.tab-pane:not(.lazy)', tabControl).each(function() { $('[data-target="#' + $(this).attr('id') + '"]', tabControl) .closest('li') .toggle(!!$('> .form-group:not(:empty):not(.hide)', $(this)).length) diff --git a/modules/backend/widgets/form/partials/_form_tabs.htm b/modules/backend/widgets/form/partials/_form_tabs.htm index 1cbddcca19..4ff1e02048 100644 --- a/modules/backend/widgets/form/partials/_form_tabs.htm +++ b/modules/backend/widgets/form/partials/_form_tabs.htm @@ -14,7 +14,10 @@
    - $fields): ?> -
    - makePartial('form_fields', ['fields' => $fields]) ?> -
    + $fields): + $lazy = in_array($name, $tabs->lazy); + ?> +
    + + makePartial('form_tabs_lazy', ['fields' => $fields]) ?> + + makePartial('form_fields', ['fields' => $fields]) ?> + +
    diff --git a/modules/backend/widgets/form/partials/_form_tabs_lazy.htm b/modules/backend/widgets/form/partials/_form_tabs_lazy.htm new file mode 100644 index 0000000000..4d75345873 --- /dev/null +++ b/modules/backend/widgets/form/partials/_form_tabs_lazy.htm @@ -0,0 +1,33 @@ +
    +
    + +
    +
    +type, $ignoredTypes)) continue; + + $isMultiValue = is_array($field->value); + foreach (array_wrap($field->value) as $index => $value): + // Use array field names if the field has multiple values (repeater, checkboxlist, etc.). + $fieldName = $isMultiValue ? sprintf('%s[%s]', $field->getName(), $index) : $field->getName(); + + $valueIsArray = is_array($value); + foreach (array_wrap($value) as $index => $value): + // Set the correct array keys if the value is an array (repeater form fields). + $currentFieldName = $valueIsArray ? sprintf('%s[%s]', $fieldName, $index) : $fieldName; +?> + getAttributes() ?> + /> + + + From 51787164e4f5e9717496834b5c0742d53be3abfa Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Mon, 9 Dec 2019 20:58:16 +1100 Subject: [PATCH 138/157] Fixes typo in merge conflict --- modules/backend/widgets/form/partials/_form_tabs.htm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/backend/widgets/form/partials/_form_tabs.htm b/modules/backend/widgets/form/partials/_form_tabs.htm index 4ff1e02048..83d1fa25fb 100644 --- a/modules/backend/widgets/form/partials/_form_tabs.htm +++ b/modules/backend/widgets/form/partials/_form_tabs.htm @@ -18,7 +18,7 @@ $lazy = in_array($name, $tabs->lazy); ?>
  • - + getIcon($name)): ?> From 4f9671fb32db57b917722c1a08996f7e15f237f1 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Mon, 9 Dec 2019 22:05:39 +1100 Subject: [PATCH 139/157] Add 7.4 test back in --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b6e29f9a4a..072b795dac 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,7 +13,7 @@ jobs: strategy: max-parallel: 6 matrix: - phpVersions: ['7.1', '7.2', '7.3'] + phpVersions: ['7.1', '7.2', '7.3', '7.4'] fail-fast: false name: PHP ${{ matrix.phpVersions }} steps: From 0bc13179b74732d140a8768093420e5833d27add Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Mon, 9 Dec 2019 22:56:51 +1100 Subject: [PATCH 140/157] Monkey patch PHPUnit\Framework\MockObject\Generator This avoids "Function ReflectionType::__toString() is deprecated" warnings --- tests/bootstrap.php | 11 + tests/resources/patches/php-generator-7.php | 1184 +++++++++++++++++++ 2 files changed, 1195 insertions(+) create mode 100644 tests/resources/patches/php-generator-7.php diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 5ed3e12968..e7e53fd1af 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -19,3 +19,14 @@ 'modules', 'plugins' ]); + +/* + * Monkey patch PHPUnit\Framework\MockObject\Generator to avoid + * "Function ReflectionType::__toString() is deprecated" warnings + */ +$generatorPatchPath = __DIR__ . '/resources/patches/php-generator-7.php'; +$generatorSourcePath = __DIR__ . '/../vendor/phpunit/phpunit-mock-objects/src/Generator.php'; + +if (file_exists($generatorSourcePath)) { + file_put_contents($generatorSourcePath, file_get_contents($generatorPatchPath)); +} diff --git a/tests/resources/patches/php-generator-7.php b/tests/resources/patches/php-generator-7.php new file mode 100644 index 0000000000..4927424b96 --- /dev/null +++ b/tests/resources/patches/php-generator-7.php @@ -0,0 +1,1184 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + * Patched with: https://github.com/sebastianbergmann/phpunit/pull/3765/files + */ +namespace PHPUnit\Framework\MockObject; + +use Doctrine\Instantiator\Exception\ExceptionInterface as InstantiatorException; +use Doctrine\Instantiator\Instantiator; +use Iterator; +use IteratorAggregate; +use PHPUnit\Framework\Exception; +use PHPUnit\Util\InvalidArgumentHelper; +use ReflectionClass; +use ReflectionException; +use ReflectionMethod; +use SoapClient; +use Text_Template; +use Traversable; + +/** + * Mock Object Code Generator + */ +class Generator +{ + /** + * @var array + */ + private static $cache = []; + + /** + * @var Text_Template[] + */ + private static $templates = []; + + /** + * @var array + */ + private $blacklistedMethodNames = [ + '__CLASS__' => true, + '__DIR__' => true, + '__FILE__' => true, + '__FUNCTION__' => true, + '__LINE__' => true, + '__METHOD__' => true, + '__NAMESPACE__' => true, + '__TRAIT__' => true, + '__clone' => true, + '__halt_compiler' => true, + ]; + + /** + * Returns a mock object for the specified class. + * + * @param string|string[] $type + * @param array $methods + * @param array $arguments + * @param string $mockClassName + * @param bool $callOriginalConstructor + * @param bool $callOriginalClone + * @param bool $callAutoload + * @param bool $cloneArguments + * @param bool $callOriginalMethods + * @param object $proxyTarget + * @param bool $allowMockingUnknownTypes + * + * @return MockObject + * + * @throws Exception + * @throws RuntimeException + * @throws \PHPUnit\Framework\Exception + * @throws \ReflectionException + */ + public function getMock($type, $methods = [], array $arguments = [], $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $cloneArguments = true, $callOriginalMethods = false, $proxyTarget = null, $allowMockingUnknownTypes = true) + { + if (!\is_array($type) && !\is_string($type)) { + throw InvalidArgumentHelper::factory(1, 'array or string'); + } + + if (!\is_string($mockClassName)) { + throw InvalidArgumentHelper::factory(4, 'string'); + } + + if (!\is_array($methods) && null !== $methods) { + throw InvalidArgumentHelper::factory(2, 'array', $methods); + } + + if ($type === 'Traversable' || $type === '\\Traversable') { + $type = 'Iterator'; + } + + if (\is_array($type)) { + $type = \array_unique( + \array_map( + function ($type) { + if ($type === 'Traversable' || + $type === '\\Traversable' || + $type === '\\Iterator') { + return 'Iterator'; + } + + return $type; + }, + $type + ) + ); + } + + if (!$allowMockingUnknownTypes) { + if (\is_array($type)) { + foreach ($type as $_type) { + if (!\class_exists($_type, $callAutoload) && + !\interface_exists($_type, $callAutoload)) { + throw new RuntimeException( + \sprintf( + 'Cannot stub or mock class or interface "%s" which does not exist', + $_type + ) + ); + } + } + } else { + if (!\class_exists($type, $callAutoload) && + !\interface_exists($type, $callAutoload) + ) { + throw new RuntimeException( + \sprintf( + 'Cannot stub or mock class or interface "%s" which does not exist', + $type + ) + ); + } + } + } + + if (null !== $methods) { + foreach ($methods as $method) { + if (!\preg_match('~[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*~', $method)) { + throw new RuntimeException( + \sprintf( + 'Cannot stub or mock method with invalid name "%s"', + $method + ) + ); + } + } + + if ($methods !== \array_unique($methods)) { + throw new RuntimeException( + \sprintf( + 'Cannot stub or mock using a method list that contains duplicates: "%s" (duplicate: "%s")', + \implode(', ', $methods), + \implode(', ', \array_unique(\array_diff_assoc($methods, \array_unique($methods)))) + ) + ); + } + } + + if ($mockClassName !== '' && \class_exists($mockClassName, false)) { + $reflect = new ReflectionClass($mockClassName); + + if (!$reflect->implementsInterface(MockObject::class)) { + throw new RuntimeException( + \sprintf( + 'Class "%s" already exists.', + $mockClassName + ) + ); + } + } + + if ($callOriginalConstructor === false && $callOriginalMethods === true) { + throw new RuntimeException( + 'Proxying to original methods requires invoking the original constructor' + ); + } + + $mock = $this->generate( + $type, + $methods, + $mockClassName, + $callOriginalClone, + $callAutoload, + $cloneArguments, + $callOriginalMethods + ); + + return $this->getObject( + $mock['code'], + $mock['mockClassName'], + $type, + $callOriginalConstructor, + $callAutoload, + $arguments, + $callOriginalMethods, + $proxyTarget + ); + } + + /** + * @param string $code + * @param string $className + * @param array|string $type + * @param bool $callOriginalConstructor + * @param bool $callAutoload + * @param array $arguments + * @param bool $callOriginalMethods + * @param object $proxyTarget + * + * @return MockObject + * + * @throws \ReflectionException + * @throws RuntimeException + */ + private function getObject($code, $className, $type = '', $callOriginalConstructor = false, $callAutoload = false, array $arguments = [], $callOriginalMethods = false, $proxyTarget = null) + { + $this->evalClass($code, $className); + + if ($callOriginalConstructor && + \is_string($type) && + !\interface_exists($type, $callAutoload)) { + if (\count($arguments) === 0) { + $object = new $className; + } else { + $class = new ReflectionClass($className); + $object = $class->newInstanceArgs($arguments); + } + } else { + try { + $instantiator = new Instantiator; + $object = $instantiator->instantiate($className); + } catch (InstantiatorException $exception) { + throw new RuntimeException($exception->getMessage()); + } + } + + if ($callOriginalMethods) { + if (!\is_object($proxyTarget)) { + if (\count($arguments) === 0) { + $proxyTarget = new $type; + } else { + $class = new ReflectionClass($type); + $proxyTarget = $class->newInstanceArgs($arguments); + } + } + + $object->__phpunit_setOriginalObject($proxyTarget); + } + + return $object; + } + + /** + * @param string $code + * @param string $className + */ + private function evalClass($code, $className) + { + if (!\class_exists($className, false)) { + eval($code); + } + } + + /** + * Returns a mock object for the specified abstract class with all abstract + * methods of the class mocked. Concrete methods to mock can be specified with + * the last parameter + * + * @param string $originalClassName + * @param array $arguments + * @param string $mockClassName + * @param bool $callOriginalConstructor + * @param bool $callOriginalClone + * @param bool $callAutoload + * @param array $mockedMethods + * @param bool $cloneArguments + * + * @return MockObject + * + * @throws \ReflectionException + * @throws RuntimeException + * @throws Exception + */ + public function getMockForAbstractClass($originalClassName, array $arguments = [], $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $mockedMethods = [], $cloneArguments = true) + { + if (!\is_string($originalClassName)) { + throw InvalidArgumentHelper::factory(1, 'string'); + } + + if (!\is_string($mockClassName)) { + throw InvalidArgumentHelper::factory(3, 'string'); + } + + if (\class_exists($originalClassName, $callAutoload) || + \interface_exists($originalClassName, $callAutoload)) { + $reflector = new ReflectionClass($originalClassName); + $methods = $mockedMethods; + + foreach ($reflector->getMethods() as $method) { + if ($method->isAbstract() && !\in_array($method->getName(), $methods)) { + $methods[] = $method->getName(); + } + } + + if (empty($methods)) { + $methods = null; + } + + return $this->getMock( + $originalClassName, + $methods, + $arguments, + $mockClassName, + $callOriginalConstructor, + $callOriginalClone, + $callAutoload, + $cloneArguments + ); + } + + throw new RuntimeException( + \sprintf('Class "%s" does not exist.', $originalClassName) + ); + } + + /** + * Returns a mock object for the specified trait with all abstract methods + * of the trait mocked. Concrete methods to mock can be specified with the + * `$mockedMethods` parameter. + * + * @param string $traitName + * @param array $arguments + * @param string $mockClassName + * @param bool $callOriginalConstructor + * @param bool $callOriginalClone + * @param bool $callAutoload + * @param array $mockedMethods + * @param bool $cloneArguments + * + * @return MockObject + * + * @throws \ReflectionException + * @throws RuntimeException + * @throws Exception + */ + public function getMockForTrait($traitName, array $arguments = [], $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $mockedMethods = [], $cloneArguments = true) + { + if (!\is_string($traitName)) { + throw InvalidArgumentHelper::factory(1, 'string'); + } + + if (!\is_string($mockClassName)) { + throw InvalidArgumentHelper::factory(3, 'string'); + } + + if (!\trait_exists($traitName, $callAutoload)) { + throw new RuntimeException( + \sprintf( + 'Trait "%s" does not exist.', + $traitName + ) + ); + } + + $className = $this->generateClassName( + $traitName, + '', + 'Trait_' + ); + + $classTemplate = $this->getTemplate('trait_class.tpl'); + + $classTemplate->setVar( + [ + 'prologue' => 'abstract ', + 'class_name' => $className['className'], + 'trait_name' => $traitName + ] + ); + + $this->evalClass( + $classTemplate->render(), + $className['className'] + ); + + return $this->getMockForAbstractClass($className['className'], $arguments, $mockClassName, $callOriginalConstructor, $callOriginalClone, $callAutoload, $mockedMethods, $cloneArguments); + } + + /** + * Returns an object for the specified trait. + * + * @param string $traitName + * @param array $arguments + * @param string $traitClassName + * @param bool $callOriginalConstructor + * @param bool $callOriginalClone + * @param bool $callAutoload + * + * @return object + * + * @throws \ReflectionException + * @throws RuntimeException + * @throws Exception + */ + public function getObjectForTrait($traitName, array $arguments = [], $traitClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true) + { + if (!\is_string($traitName)) { + throw InvalidArgumentHelper::factory(1, 'string'); + } + + if (!\is_string($traitClassName)) { + throw InvalidArgumentHelper::factory(3, 'string'); + } + + if (!\trait_exists($traitName, $callAutoload)) { + throw new RuntimeException( + \sprintf( + 'Trait "%s" does not exist.', + $traitName + ) + ); + } + + $className = $this->generateClassName( + $traitName, + $traitClassName, + 'Trait_' + ); + + $classTemplate = $this->getTemplate('trait_class.tpl'); + + $classTemplate->setVar( + [ + 'prologue' => '', + 'class_name' => $className['className'], + 'trait_name' => $traitName + ] + ); + + return $this->getObject($classTemplate->render(), $className['className']); + } + + /** + * @param array|string $type + * @param array $methods + * @param string $mockClassName + * @param bool $callOriginalClone + * @param bool $callAutoload + * @param bool $cloneArguments + * @param bool $callOriginalMethods + * + * @return array + * + * @throws \ReflectionException + * @throws \PHPUnit\Framework\MockObject\RuntimeException + */ + public function generate($type, array $methods = null, $mockClassName = '', $callOriginalClone = true, $callAutoload = true, $cloneArguments = true, $callOriginalMethods = false) + { + if (\is_array($type)) { + \sort($type); + } + + if ($mockClassName === '') { + $key = \md5( + \is_array($type) ? \implode('_', $type) : $type . + \serialize($methods) . + \serialize($callOriginalClone) . + \serialize($cloneArguments) . + \serialize($callOriginalMethods) + ); + + if (isset(self::$cache[$key])) { + return self::$cache[$key]; + } + } + + $mock = $this->generateMock( + $type, + $methods, + $mockClassName, + $callOriginalClone, + $callAutoload, + $cloneArguments, + $callOriginalMethods + ); + + if (isset($key)) { + self::$cache[$key] = $mock; + } + + return $mock; + } + + /** + * @param string $wsdlFile + * @param string $className + * @param array $methods + * @param array $options + * + * @return string + * + * @throws RuntimeException + */ + public function generateClassFromWsdl($wsdlFile, $className, array $methods = [], array $options = []) + { + if (!\extension_loaded('soap')) { + throw new RuntimeException( + 'The SOAP extension is required to generate a mock object from WSDL.' + ); + } + + $options = \array_merge($options, ['cache_wsdl' => WSDL_CACHE_NONE]); + $client = new SoapClient($wsdlFile, $options); + $_methods = \array_unique($client->__getFunctions()); + unset($client); + + \sort($_methods); + + $methodTemplate = $this->getTemplate('wsdl_method.tpl'); + $methodsBuffer = ''; + + foreach ($_methods as $method) { + $nameStart = \strpos($method, ' ') + 1; + $nameEnd = \strpos($method, '('); + $name = \substr($method, $nameStart, $nameEnd - $nameStart); + + if (empty($methods) || \in_array($name, $methods)) { + $args = \explode( + ',', + \substr( + $method, + $nameEnd + 1, + \strpos($method, ')') - $nameEnd - 1 + ) + ); + + foreach (\range(0, \count($args) - 1) as $i) { + $args[$i] = \substr($args[$i], \strpos($args[$i], '$')); + } + + $methodTemplate->setVar( + [ + 'method_name' => $name, + 'arguments' => \implode(', ', $args) + ] + ); + + $methodsBuffer .= $methodTemplate->render(); + } + } + + $optionsBuffer = 'array('; + + foreach ($options as $key => $value) { + $optionsBuffer .= $key . ' => ' . $value; + } + + $optionsBuffer .= ')'; + + $classTemplate = $this->getTemplate('wsdl_class.tpl'); + $namespace = ''; + + if (\strpos($className, '\\') !== false) { + $parts = \explode('\\', $className); + $className = \array_pop($parts); + $namespace = 'namespace ' . \implode('\\', $parts) . ';' . "\n\n"; + } + + $classTemplate->setVar( + [ + 'namespace' => $namespace, + 'class_name' => $className, + 'wsdl' => $wsdlFile, + 'options' => $optionsBuffer, + 'methods' => $methodsBuffer + ] + ); + + return $classTemplate->render(); + } + + /** + * @param array|string $type + * @param array|null $methods + * @param string $mockClassName + * @param bool $callOriginalClone + * @param bool $callAutoload + * @param bool $cloneArguments + * @param bool $callOriginalMethods + * + * @return array + * + * @throws \InvalidArgumentException + * @throws \ReflectionException + * @throws RuntimeException + */ + private function generateMock($type, $methods, $mockClassName, $callOriginalClone, $callAutoload, $cloneArguments, $callOriginalMethods) + { + $methodReflections = []; + $classTemplate = $this->getTemplate('mocked_class.tpl'); + + $additionalInterfaces = []; + $cloneTemplate = ''; + $isClass = false; + $isInterface = false; + $isMultipleInterfaces = false; + + if (\is_array($type)) { + foreach ($type as $_type) { + if (!\interface_exists($_type, $callAutoload)) { + throw new RuntimeException( + \sprintf( + 'Interface "%s" does not exist.', + $_type + ) + ); + } + + $isMultipleInterfaces = true; + + $additionalInterfaces[] = $_type; + $typeClass = new ReflectionClass($this->generateClassName( + $_type, + $mockClassName, + 'Mock_' + )['fullClassName'] + ); + + foreach ($this->getClassMethods($_type) as $method) { + if (\in_array($method, $methods)) { + throw new RuntimeException( + \sprintf( + 'Duplicate method "%s" not allowed.', + $method + ) + ); + } + + $methodReflections[$method] = $typeClass->getMethod($method); + $methods[] = $method; + } + } + } + + $mockClassName = $this->generateClassName( + $type, + $mockClassName, + 'Mock_' + ); + + if (\class_exists($mockClassName['fullClassName'], $callAutoload)) { + $isClass = true; + } elseif (\interface_exists($mockClassName['fullClassName'], $callAutoload)) { + $isInterface = true; + } + + if (!$isClass && !$isInterface) { + $prologue = 'class ' . $mockClassName['originalClassName'] . "\n{\n}\n\n"; + + if (!empty($mockClassName['namespaceName'])) { + $prologue = 'namespace ' . $mockClassName['namespaceName'] . + " {\n\n" . $prologue . "}\n\n" . + "namespace {\n\n"; + + $epilogue = "\n\n}"; + } + + $cloneTemplate = $this->getTemplate('mocked_clone.tpl'); + } else { + $class = new ReflectionClass($mockClassName['fullClassName']); + + if ($class->isFinal()) { + throw new RuntimeException( + \sprintf( + 'Class "%s" is declared "final" and cannot be mocked.', + $mockClassName['fullClassName'] + ) + ); + } + + if ($class->hasMethod('__clone')) { + $cloneMethod = $class->getMethod('__clone'); + + if (!$cloneMethod->isFinal()) { + if ($callOriginalClone && !$isInterface) { + $cloneTemplate = $this->getTemplate('unmocked_clone.tpl'); + } else { + $cloneTemplate = $this->getTemplate('mocked_clone.tpl'); + } + } + } else { + $cloneTemplate = $this->getTemplate('mocked_clone.tpl'); + } + } + + if (\is_object($cloneTemplate)) { + $cloneTemplate = $cloneTemplate->render(); + } + + if (\is_array($methods) && empty($methods) && + ($isClass || $isInterface)) { + $methods = $this->getClassMethods($mockClassName['fullClassName']); + } + + if (!\is_array($methods)) { + $methods = []; + } + + $mockedMethods = ''; + $configurable = []; + + foreach ($methods as $methodName) { + if ($methodName !== '__construct' && $methodName !== '__clone') { + $configurable[] = \strtolower($methodName); + } + } + + if (isset($class)) { + // https://github.com/sebastianbergmann/phpunit-mock-objects/issues/103 + if ($isInterface && $class->implementsInterface(Traversable::class) && + !$class->implementsInterface(Iterator::class) && + !$class->implementsInterface(IteratorAggregate::class)) { + $additionalInterfaces[] = Iterator::class; + $methods = \array_merge($methods, $this->getClassMethods(Iterator::class)); + } + + foreach ($methods as $methodName) { + try { + $method = $class->getMethod($methodName); + + if ($this->canMockMethod($method)) { + $mockedMethods .= $this->generateMockedMethodDefinitionFromExisting( + $method, + $cloneArguments, + $callOriginalMethods + ); + } + } catch (ReflectionException $e) { + $mockedMethods .= $this->generateMockedMethodDefinition( + $mockClassName['fullClassName'], + $methodName, + $cloneArguments + ); + } + } + } elseif ($isMultipleInterfaces) { + foreach ($methods as $methodName) { + if ($this->canMockMethod($methodReflections[$methodName])) { + $mockedMethods .= $this->generateMockedMethodDefinitionFromExisting( + $methodReflections[$methodName], + $cloneArguments, + $callOriginalMethods + ); + } + } + } else { + foreach ($methods as $methodName) { + $mockedMethods .= $this->generateMockedMethodDefinition( + $mockClassName['fullClassName'], + $methodName, + $cloneArguments + ); + } + } + + $method = ''; + + if (!\in_array('method', $methods) && (!isset($class) || !$class->hasMethod('method'))) { + $methodTemplate = $this->getTemplate('mocked_class_method.tpl'); + + $method = $methodTemplate->render(); + } + + $classTemplate->setVar( + [ + 'prologue' => $prologue ?? '', + 'epilogue' => $epilogue ?? '', + 'class_declaration' => $this->generateMockClassDeclaration( + $mockClassName, + $isInterface, + $additionalInterfaces + ), + 'clone' => $cloneTemplate, + 'mock_class_name' => $mockClassName['className'], + 'mocked_methods' => $mockedMethods, + 'method' => $method, + 'configurable' => '[' . \implode(', ', \array_map(function ($m) { + return '\'' . $m . '\''; + }, $configurable)) . ']' + ] + ); + + return [ + 'code' => $classTemplate->render(), + 'mockClassName' => $mockClassName['className'] + ]; + } + + /** + * @param array|string $type + * @param string $className + * @param string $prefix + * + * @return array + */ + private function generateClassName($type, $className, $prefix) + { + if (\is_array($type)) { + $type = \implode('_', $type); + } + + if ($type[0] === '\\') { + $type = \substr($type, 1); + } + + $classNameParts = \explode('\\', $type); + + if (\count($classNameParts) > 1) { + $type = \array_pop($classNameParts); + $namespaceName = \implode('\\', $classNameParts); + $fullClassName = $namespaceName . '\\' . $type; + } else { + $namespaceName = ''; + $fullClassName = $type; + } + + if ($className === '') { + do { + $className = $prefix . $type . '_' . + \substr(\md5(\mt_rand()), 0, 8); + } while (\class_exists($className, false)); + } + + return [ + 'className' => $className, + 'originalClassName' => $type, + 'fullClassName' => $fullClassName, + 'namespaceName' => $namespaceName + ]; + } + + /** + * @param array $mockClassName + * @param bool $isInterface + * @param array $additionalInterfaces + * + * @return string + */ + private function generateMockClassDeclaration(array $mockClassName, $isInterface, array $additionalInterfaces = []) + { + $buffer = 'class '; + + $additionalInterfaces[] = MockObject::class; + $interfaces = \implode(', ', $additionalInterfaces); + + if ($isInterface) { + $buffer .= \sprintf( + '%s implements %s', + $mockClassName['className'], + $interfaces + ); + + if (!\in_array($mockClassName['originalClassName'], $additionalInterfaces)) { + $buffer .= ', '; + + if (!empty($mockClassName['namespaceName'])) { + $buffer .= $mockClassName['namespaceName'] . '\\'; + } + + $buffer .= $mockClassName['originalClassName']; + } + } else { + $buffer .= \sprintf( + '%s extends %s%s implements %s', + $mockClassName['className'], + !empty($mockClassName['namespaceName']) ? $mockClassName['namespaceName'] . '\\' : '', + $mockClassName['originalClassName'], + $interfaces + ); + } + + return $buffer; + } + + /** + * @param ReflectionMethod $method + * @param bool $cloneArguments + * @param bool $callOriginalMethods + * + * @return string + * + * @throws \PHPUnit\Framework\MockObject\RuntimeException + */ + private function generateMockedMethodDefinitionFromExisting(ReflectionMethod $method, $cloneArguments, $callOriginalMethods) + { + if ($method->isPrivate()) { + $modifier = 'private'; + } elseif ($method->isProtected()) { + $modifier = 'protected'; + } else { + $modifier = 'public'; + } + + if ($method->isStatic()) { + $modifier .= ' static'; + } + + if ($method->returnsReference()) { + $reference = '&'; + } else { + $reference = ''; + } + + if ($method->hasReturnType()) { + $returnType = $method->getReturnType()->getName(); + } else { + $returnType = ''; + } + + if (\preg_match('#\*[ \t]*+@deprecated[ \t]*+(.*?)\r?+\n[ \t]*+\*(?:[ \t]*+@|/$)#s', $method->getDocComment(), $deprecation)) { + $deprecation = \trim(\preg_replace('#[ \t]*\r?\n[ \t]*+\*[ \t]*+#', ' ', $deprecation[1])); + } else { + $deprecation = false; + } + + return $this->generateMockedMethodDefinition( + $method->getDeclaringClass()->getName(), + $method->getName(), + $cloneArguments, + $modifier, + $this->getMethodParameters($method), + $this->getMethodParameters($method, true), + $returnType, + $reference, + $callOriginalMethods, + $method->isStatic(), + $deprecation, + $method->hasReturnType() && PHP_VERSION_ID >= 70100 && $method->getReturnType()->allowsNull() + ); + } + + /** + * @param string $className + * @param string $methodName + * @param bool $cloneArguments + * @param string $modifier + * @param string $argumentsForDeclaration + * @param string $argumentsForCall + * @param string $returnType + * @param string $reference + * @param bool $callOriginalMethods + * @param bool $static + * @param bool|string $deprecation + * @param bool $allowsReturnNull + * + * @return string + * + * @throws \InvalidArgumentException + */ + private function generateMockedMethodDefinition($className, $methodName, $cloneArguments = true, $modifier = 'public', $argumentsForDeclaration = '', $argumentsForCall = '', $returnType = '', $reference = '', $callOriginalMethods = false, $static = false, $deprecation = false, $allowsReturnNull = false) + { + if ($static) { + $templateFile = 'mocked_static_method.tpl'; + } else { + if ($returnType === 'void') { + $templateFile = \sprintf( + '%s_method_void.tpl', + $callOriginalMethods ? 'proxied' : 'mocked' + ); + } else { + $templateFile = \sprintf( + '%s_method.tpl', + $callOriginalMethods ? 'proxied' : 'mocked' + ); + } + } + + // Mocked interfaces returning 'self' must explicitly declare the + // interface name as the return type. See + // https://bugs.php.net/bug.php?id=70722 + if ($returnType === 'self') { + $returnType = $className; + } + + if (false !== $deprecation) { + $deprecation = "The $className::$methodName method is deprecated ($deprecation)."; + $deprecationTemplate = $this->getTemplate('deprecation.tpl'); + + $deprecationTemplate->setVar( + [ + 'deprecation' => \var_export($deprecation, true), + ] + ); + + $deprecation = $deprecationTemplate->render(); + } + + $template = $this->getTemplate($templateFile); + + $template->setVar( + [ + 'arguments_decl' => $argumentsForDeclaration, + 'arguments_call' => $argumentsForCall, + 'return_delim' => $returnType ? ': ' : '', + 'return_type' => $allowsReturnNull ? '?' . $returnType : $returnType, + 'arguments_count' => !empty($argumentsForCall) ? \substr_count($argumentsForCall, ',') + 1 : 0, + 'class_name' => $className, + 'method_name' => $methodName, + 'modifier' => $modifier, + 'reference' => $reference, + 'clone_arguments' => $cloneArguments ? 'true' : 'false', + 'deprecation' => $deprecation + ] + ); + + return $template->render(); + } + + /** + * @param ReflectionMethod $method + * + * @return bool + * + * @throws \ReflectionException + */ + private function canMockMethod(ReflectionMethod $method) + { + return !($method->isConstructor() || $method->isFinal() || $method->isPrivate() || $this->isMethodNameBlacklisted($method->getName())); + } + + /** + * Returns whether a method name is blacklisted + * + * @param string $name + * + * @return bool + */ + private function isMethodNameBlacklisted($name) + { + return isset($this->blacklistedMethodNames[$name]); + } + + /** + * Returns the parameters of a function or method. + * + * @param ReflectionMethod $method + * @param bool $forCall + * + * @return string + * + * @throws RuntimeException + */ + private function getMethodParameters(ReflectionMethod $method, $forCall = false) + { + $parameters = []; + + foreach ($method->getParameters() as $i => $parameter) { + $name = '$' . $parameter->getName(); + + /* Note: PHP extensions may use empty names for reference arguments + * or "..." for methods taking a variable number of arguments. + */ + if ($name === '$' || $name === '$...') { + $name = '$arg' . $i; + } + + if ($parameter->isVariadic()) { + if ($forCall) { + continue; + } + + $name = '...' . $name; + } + + $nullable = ''; + $default = ''; + $reference = ''; + $typeDeclaration = ''; + + if (!$forCall) { + if (PHP_VERSION_ID >= 70100 && $parameter->hasType() && $parameter->allowsNull()) { + $nullable = '?'; + } + + if ($parameter->hasType() && $parameter->getType()->getName() !== 'self') { + $typeDeclaration = $parameter->getType()->getName() . ' '; + } elseif ($parameter->isArray()) { + $typeDeclaration = 'array '; + } elseif ($parameter->isCallable()) { + $typeDeclaration = 'callable '; + } else { + try { + $class = $parameter->getClass(); + } catch (ReflectionException $e) { + throw new RuntimeException( + \sprintf( + 'Cannot mock %s::%s() because a class or ' . + 'interface used in the signature is not loaded', + $method->getDeclaringClass()->getName(), + $method->getName() + ), + 0, + $e + ); + } + + if ($class !== null) { + $typeDeclaration = $class->getName() . ' '; + } + } + + if (!$parameter->isVariadic()) { + if ($parameter->isDefaultValueAvailable()) { + $value = $parameter->getDefaultValueConstantName(); + + if ($value === null) { + $value = \var_export($parameter->getDefaultValue(), true); + } elseif (!\defined($value)) { + $rootValue = \preg_replace('/^.*\\\\/', '', $value); + $value = \defined($rootValue) ? $rootValue : $value; + } + + $default = ' = ' . $value; + } elseif ($parameter->isOptional()) { + $default = ' = null'; + } + } + } + + if ($parameter->isPassedByReference()) { + $reference = '&'; + } + + $parameters[] = $nullable . $typeDeclaration . $reference . $name . $default; + } + + return \implode(', ', $parameters); + } + + /** + * @param string $className + * + * @return array + * + * @throws \ReflectionException + */ + public function getClassMethods($className) + { + $class = new ReflectionClass($className); + $methods = []; + + foreach ($class->getMethods() as $method) { + if ($method->isPublic() || $method->isAbstract()) { + $methods[] = $method->getName(); + } + } + + return $methods; + } + + /** + * @param string $template + * + * @return Text_Template + * + * @throws \InvalidArgumentException + */ + private function getTemplate($template) + { + $filename = __DIR__ . DIRECTORY_SEPARATOR . 'Generator' . DIRECTORY_SEPARATOR . $template; + + if (!isset(self::$templates[$filename])) { + self::$templates[$filename] = new Text_Template($filename); + } + + return self::$templates[$filename]; + } +} From a164dfc7c7952c9140cdd45f3d8428f5b18422a0 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Mon, 9 Dec 2019 23:03:03 +1100 Subject: [PATCH 141/157] Tell codesniffer to ignore this patched file --- tests/resources/patches/php-generator-7.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/resources/patches/php-generator-7.php b/tests/resources/patches/php-generator-7.php index 4927424b96..677680d692 100644 --- a/tests/resources/patches/php-generator-7.php +++ b/tests/resources/patches/php-generator-7.php @@ -1,4 +1,5 @@ Date: Mon, 9 Dec 2019 23:16:06 +1100 Subject: [PATCH 142/157] October is a platform, powered by a framework :-) Ref https://octobercms.com/blog/post/putting-octobercms-words --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 362c4aab1f..de8b75333f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ October

    -[October](https://octobercms.com) is a Content Management Framework (CMF) and web platform whose sole purpose is to make your development workflow simple again. It was born out of frustration with existing systems. We feel building websites has become a convoluted and confusing process that leaves developers unsatisfied. We want to turn you around to the simpler side and get back to basics. +[October](https://octobercms.com) is a Content Management System (CMS) and web platform whose sole purpose is to make your development workflow simple again. It was born out of frustration with existing systems. We feel building websites has become a convoluted and confusing process that leaves developers unsatisfied. We want to turn you around to the simpler side and get back to basics. October's mission is to show the world that web development is not rocket science. From 0a63d0edd7ef7dbcb962b4342b92a1117f2ac598 Mon Sep 17 00:00:00 2001 From: Marc Jauvin Date: Mon, 9 Dec 2019 08:05:50 -0500 Subject: [PATCH 143/157] Make CMS object code editor read-only in safe mode (#4769) Adds a dismissable message to the CMS object code editor indicating that the PHP code section of a CMS object cannot be edited when `cms.enableSafeMode` is `true` (or when debugging is disabled if `null`). Credit to @mjauvin. --- modules/cms/classes/CmsCompoundObject.php | 8 ++------ modules/cms/classes/layout/fields.yaml | 6 ++++++ modules/cms/classes/page/fields.yaml | 6 ++++++ modules/cms/classes/partial/fields.yaml | 6 ++++++ modules/cms/controllers/Index.php | 15 +++++++++++++++ .../cms/controllers/index/_safemode_notice.htm | 6 ++++++ modules/cms/helpers/Cms.php | 10 ++++++++++ modules/cms/lang/en/lang.php | 2 +- 8 files changed, 52 insertions(+), 7 deletions(-) create mode 100644 modules/cms/controllers/index/_safemode_notice.htm diff --git a/modules/cms/classes/CmsCompoundObject.php b/modules/cms/classes/CmsCompoundObject.php index 856d7d2588..5705515bc5 100644 --- a/modules/cms/classes/CmsCompoundObject.php +++ b/modules/cms/classes/CmsCompoundObject.php @@ -7,6 +7,7 @@ use Cms\Twig\Loader as TwigLoader; use Cms\Twig\Extension as CmsTwigExtension; use Cms\Components\ViewBag; +use Cms\Helpers\Cms as CmsHelpers; use System\Twig\Extension as SystemTwigExtension; use October\Rain\Halcyon\Processors\SectionParser; use Twig\Source as TwigSource; @@ -143,12 +144,7 @@ protected function parseSettings() */ protected function checkSafeMode() { - $safeMode = Config::get('cms.enableSafeMode', null); - if ($safeMode === null) { - $safeMode = !Config::get('app.debug', false); - } - - if ($safeMode && $this->isDirty('code') && strlen(trim($this->code))) { + if (CmsHelpers::safeModeEnabled() && $this->isDirty('code') && strlen(trim($this->code))) { throw new ApplicationException(Lang::get('cms::lang.cms_object.safe_mode_enabled')); } } diff --git a/modules/cms/classes/layout/fields.yaml b/modules/cms/classes/layout/fields.yaml index 3c02f16d3f..62c292114d 100644 --- a/modules/cms/classes/layout/fields.yaml +++ b/modules/cms/classes/layout/fields.yaml @@ -32,6 +32,12 @@ secondaryTabs: type: codeeditor language: twig + safemode_notice: + tab: cms::lang.editor.code + type: partial + hidden: true + cssClass: p-b-0 + code: tab: cms::lang.editor.code stretch: true diff --git a/modules/cms/classes/page/fields.yaml b/modules/cms/classes/page/fields.yaml index 44c56a5e90..ac754d31eb 100644 --- a/modules/cms/classes/page/fields.yaml +++ b/modules/cms/classes/page/fields.yaml @@ -74,6 +74,12 @@ secondaryTabs: type: codeeditor language: twig + safemode_notice: + tab: cms::lang.editor.code + type: partial + hidden: true + cssClass: p-b-0 + code: tab: cms::lang.editor.code stretch: true diff --git a/modules/cms/classes/partial/fields.yaml b/modules/cms/classes/partial/fields.yaml index 4d23dba15f..9e5f0a8387 100644 --- a/modules/cms/classes/partial/fields.yaml +++ b/modules/cms/classes/partial/fields.yaml @@ -32,6 +32,12 @@ secondaryTabs: type: codeeditor language: twig + safemode_notice: + tab: cms::lang.editor.code + type: partial + hidden: true + cssClass: p-b-0 + code: tab: cms::lang.editor.code stretch: true diff --git a/modules/cms/controllers/Index.php b/modules/cms/controllers/Index.php index c0ecc5ae75..4f9d2e78d0 100644 --- a/modules/cms/controllers/Index.php +++ b/modules/cms/controllers/Index.php @@ -4,6 +4,7 @@ use Lang; use Flash; use Config; +use Event; use Request; use Exception; use BackendMenu; @@ -20,6 +21,7 @@ use Cms\Classes\CmsCompoundObject; use Cms\Classes\ComponentManager; use Cms\Classes\ComponentPartial; +use Cms\Helpers\Cms as CmsHelpers; use Backend\Classes\Controller; use System\Helpers\DateTime; use October\Rain\Router\Router as RainRouter; @@ -59,6 +61,19 @@ public function __construct() { parent::__construct(); + Event::listen('backend.form.extendFieldsBefore', function ($widget) { + if (!$widget->getController() instanceof Index) { + return; + } + if (!$widget->model instanceof CmsCompoundObject) { + return; + } + if (key_exists('code', $widget->secondaryTabs['fields']) && CmsHelpers::safeModeEnabled()) { + $widget->secondaryTabs['fields']['safemode_notice']['hidden'] = false; + $widget->secondaryTabs['fields']['code']['readOnly'] = true; + }; + }); + BackendMenu::setContext('October.Cms', 'cms', true); try { diff --git a/modules/cms/controllers/index/_safemode_notice.htm b/modules/cms/controllers/index/_safemode_notice.htm new file mode 100644 index 0000000000..b9e320c890 --- /dev/null +++ b/modules/cms/controllers/index/_safemode_notice.htm @@ -0,0 +1,6 @@ +
    +
    + +

    +
    +
    diff --git a/modules/cms/helpers/Cms.php b/modules/cms/helpers/Cms.php index e8195d2a52..34332c2ea9 100644 --- a/modules/cms/helpers/Cms.php +++ b/modules/cms/helpers/Cms.php @@ -2,6 +2,7 @@ use Url; use Route; +use Config; /** * CMS Helper @@ -35,4 +36,13 @@ public function url($path = null) return Url::to($path); } + + public static function safeModeEnabled() + { + $safeMode = Config::get('cms.enableSafeMode', null); + if ($safeMode === null) { + $safeMode = !Config::get('app.debug', false); + } + return $safeMode; + } } diff --git a/modules/cms/lang/en/lang.php b/modules/cms/lang/en/lang.php index a6096b04db..d3e28b27ee 100644 --- a/modules/cms/lang/en/lang.php +++ b/modules/cms/lang/en/lang.php @@ -11,7 +11,7 @@ 'error_deleting' => "Error deleting the template file ':name'. Please check write permissions.", 'delete_success' => 'Templates deleted: :count.', 'file_name_required' => 'The File Name field is required.', - 'safe_mode_enabled' => 'Safe mode is currently enabled.' + 'safe_mode_enabled' => 'Safe mode is currently enabled. Editing the PHP code of CMS templates is disabled.' ], 'dashboard' => [ 'active_theme' => [ From 9741e0e6fb5357456596eaea23b2e6a6de74625a Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Tue, 10 Dec 2019 03:12:12 +1100 Subject: [PATCH 144/157] Rollback d31006ae1a1f5a709e9a100d0096a5633ab820b5 --- modules/cms/classes/Controller.php | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/modules/cms/classes/Controller.php b/modules/cms/classes/Controller.php index 777a891475..ecb60c4486 100644 --- a/modules/cms/classes/Controller.php +++ b/modules/cms/classes/Controller.php @@ -146,17 +146,6 @@ public function run($url = '/') $url = '/'; } - /* - * Check security token. - * - * Note: Ignore AJAX requests until a CSRF policy introduced. - * - * @see \System\Traits\SecurityController - */ - if (!Request::ajax() && !$this->verifyCsrfToken()) { - return Response::make(Lang::get('system::lang.page.invalid_token.label'), 403); - } - /* * Hidden page */ @@ -389,6 +378,7 @@ public function runPage($page, $useAjax = true) if ( $useAjax && ($handler = post('_handler')) && + $this->verifyCsrfToken() && ($handlerResponse = $this->runAjaxHandler($handler)) && $handlerResponse !== true ) { From ffd6474a2c2a5d6b93609b23649696d540b64b3e Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Tue, 10 Dec 2019 19:59:49 +1100 Subject: [PATCH 145/157] ApplicationException -> SystemException This appears to be a typoe. It doesn't make sense to ever log "user errors", only "system errors" Fixes #4569 --- modules/system/classes/ErrorHandler.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/system/classes/ErrorHandler.php b/modules/system/classes/ErrorHandler.php index 910f044e8b..4a5836f05c 100644 --- a/modules/system/classes/ErrorHandler.php +++ b/modules/system/classes/ErrorHandler.php @@ -7,7 +7,7 @@ use Cms\Classes\Router; use Cms\Classes\Controller as CmsController; use October\Rain\Exception\ErrorHandler as ErrorHandlerBase; -use October\Rain\Exception\ApplicationException; +use October\Rain\Exception\SystemException; /** * System Error Handler, this class handles application exception events. @@ -36,12 +36,12 @@ class ErrorHandler extends ErrorHandlerBase /** * We are about to display an error page to the user, - * if it is an ApplicationException, this event should be logged. + * if it is an SystemException, this event should be logged. * @return void */ public function beforeHandleError($exception) { - if ($exception instanceof ApplicationException) { + if ($exception instanceof SystemException) { Log::error($exception); } } From 1aad150fd02aebf3dcedb3e6c1d8958f52795450 Mon Sep 17 00:00:00 2001 From: Robin Bonnes Date: Tue, 10 Dec 2019 10:06:10 +0100 Subject: [PATCH 146/157] Adds the ability to override the column header label in import/export. (#4737) Now we can use the `backend.list.overrideHeaderValue` event also in the import/export. --- modules/backend/behaviors/ImportExportController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/backend/behaviors/ImportExportController.php b/modules/backend/behaviors/ImportExportController.php index 61ac7551de..88e063ce76 100644 --- a/modules/backend/behaviors/ImportExportController.php +++ b/modules/backend/behaviors/ImportExportController.php @@ -629,7 +629,7 @@ public function exportFromList($definition = null, $options = []) $headers = []; $columns = $widget->getVisibleColumns(); foreach ($columns as $column) { - $headers[] = Lang::get($column->label); + $headers[] = $widget->getHeaderValue($column); } $csv->insertOne($headers); From 9ddb06ff5aff36fbf821e3d81b38045473f279c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Ora=C5=BEem?= Date: Tue, 10 Dec 2019 10:17:42 +0100 Subject: [PATCH 147/157] Slovenian language added (#4796) * Add Slovenian language --- .../assets/vendor/froala/js/languages/sl.js | 280 ++++++++ modules/backend/lang/sl/lang.php | 628 ++++++++++++++++++ modules/backend/models/Preference.php | 1 + modules/cms/lang/sl/lang.php | 301 +++++++++ modules/system/assets/js/lang/lang.sl.js | 299 +++++++++ modules/system/lang/ar/lang.php | 1 + modules/system/lang/en/lang.php | 1 + modules/system/lang/et/lang.php | 1 + modules/system/lang/fa/lang.php | 1 + modules/system/lang/fi/lang.php | 1 + modules/system/lang/lt/lang.php | 1 + modules/system/lang/nl/lang.php | 1 + modules/system/lang/pt-pt/lang.php | 1 + modules/system/lang/sk/lang.php | 1 + modules/system/lang/sl/client.php | 115 ++++ modules/system/lang/sl/lang.php | 478 +++++++++++++ modules/system/lang/sl/validation.php | 121 ++++ modules/system/lang/tr/lang.php | 1 + modules/system/lang/vn/lang.php | 1 + 19 files changed, 2234 insertions(+) create mode 100644 modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/sl.js create mode 100644 modules/backend/lang/sl/lang.php create mode 100644 modules/cms/lang/sl/lang.php create mode 100644 modules/system/assets/js/lang/lang.sl.js create mode 100644 modules/system/lang/sl/client.php create mode 100644 modules/system/lang/sl/lang.php create mode 100644 modules/system/lang/sl/validation.php diff --git a/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/sl.js b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/sl.js new file mode 100644 index 0000000000..86da844f81 --- /dev/null +++ b/modules/backend/formwidgets/richeditor/assets/vendor/froala/js/languages/sl.js @@ -0,0 +1,280 @@ +/*! + * froala_editor v2.9.3 (https://www.froala.com/wysiwyg-editor) + * License https://froala.com/wysiwyg-editor/terms/ + * Copyright 2014-2019 Froala Labs + */ + +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof module === 'object' && module.exports) { + // Node/CommonJS + module.exports = function( root, jQuery ) { + if ( jQuery === undefined ) { + // require('jQuery') returns a factory that requires window to + // build a jQuery instance, we normalize how we use modules + // that require this pattern but the window provided is a noop + // if it's defined (how jquery works) + if ( typeof window !== 'undefined' ) { + jQuery = require('jquery'); + } + else { + jQuery = require('jquery')(root); + } + } + return factory(jQuery); + }; + } else { + // Browser globals + factory(window.jQuery); + } +}(function ($) { +/** + * Slovenian + */ + +$.FE.LANGUAGE['sl'] = { + translation: { + // Place holder + "Type something": "Nekaj vtipkajte", + + // Basic formatting + "Bold": "Krepko", + "Italic": "Poševno", + "Underline": "Podčrtano", + "Strikethrough": "Prečrtano", + + // Main buttons + "Insert": "Vstavi", + "Delete": "Izbriši", + "Cancel": "Prekliči", + "OK": "OK", + "Back": "Nazaj", + "Remove": "Odstrani", + "More": "Več", + "Update": "Posodobi", + "Style": "Slog", + + // Font + "Font Family": "Oblika pisave", + "Font Size": "Velikost pisave", + + // Colors + "Colors": "Barve", + "Background": "Ozadje", + "Text": "Besedilo", + "HEX Color": "HEX barva", + + // Paragraphs + "Paragraph Format": "Oblika odstavka", + "Normal": "Normalno", + "Code": "Koda", + "Heading 1": "Naslov 1", + "Heading 2": "Naslov 2", + "Heading 3": "Naslov 3", + "Heading 4": "Naslov 4", + + // Style + "Paragraph Style": "Slog odstavka", + "Inline Style": "Vrstični slog", + + // Alignment + "Align": "Poravnava", + "Align Left": "Leva poravnava", + "Align Center": "Sredinska poravnava", + "Align Right": "Desna poravnava", + "Align Justify": "Obojestranska poravnava", + "None": "Brez poravnave", + + // Lists + "Ordered List": "Številčni seznam", + "Default": "Privzeto", + "Lower Alpha": "Latinica male", + "Lower Greek": "Grške male", + "Lower Roman": "Rimske male", + "Upper Alpha": "Latinica velike", + "Upper Roman": "Rimske velike", + + "Unordered List": "Neštevilčni seznam", + "Circle": "Krog", + "Disc": "Disk", + "Square": "Kvadrat", + + // Line height + "Line Height": "Višina vrstice", + "Single": "Enojna", + "Double": "Dvojna", + + // Indent + "Decrease Indent": "Zmanjšaj zamik", + "Increase Indent": "Povečaj zamik", + + // Links + "Insert Link": "Vstavi povezavo", + "Open in new tab": "Odpri povezavo v novem zavihku", + "Open Link": "Odpri povezavo", + "Edit Link": "Uredi povezavo", + "Unlink": "Odstrani povezavo", + "Choose Link": "Izberi povezavo", + + // Images + "Insert Image": "Vstavi sliko", + "Upload Image": "Naloži sliko", + "By URL": "Iz URL povezave", + "Browse": "Prebrskaj", + "Drop image": "Spustite sliko sem", + "or click": "ali kliknite", + "Manage Images": "Urejaj slike", + "Loading": "Nalaganje", + "Deleting": "Brisanje", + "Tags": "Značke", + "Are you sure? Image will be deleted.": "Ali ste prepričani? Slika bo izbrisana.", + "Replace": "Zamenjaj", + "Uploading": "Nalaganje", + "Loading image": "Nalagam sliko", + "Display": "Prikaži", + "Inline": "Vrstično", + "Break Text": "Prelomi besedilo", + "Alternative Text": "Nadomestno besedilo", + "Change Size": "Spremeni velikost", + "Width": "Širina", + "Height": "Višina", + "Something went wrong. Please try again.": "Nekaj je šlo narobe. Prosimo, poskusite ponovno.", + "Image Caption": "Opis slike", + "Advanced Edit": "Napredno urejanje", + + // Video + "Insert Video": "Vstavi video posnetek", + "Embedded Code": "Vdelana koda", + "Paste in a video URL": "Prilepite URL video posnetka", + "Drop video": "Spustite video posnetek sem", + "Your browser does not support HTML5 video.": "Vaš brskalnik ne podpira HTML5 video funkcionalnosti.", + "Upload Video": "Naloži video posnetek", + + // Tables + "Insert Table": "Vstavi tabelo", + "Table Header": "Glava tabele", + "Remove Table": "Odstrani tabelo", + "Table Style": "Slog tabele", + "Horizontal Align": "Horizontalna poravnava", + "Row": "Vrstica", + "Insert row above": "Vstavi vrstico nad", + "Insert row below": "Vstavi vrstico pod", + "Delete row": "Izbriši vrstico", + "Column": "Stolpec", + "Insert column before": "Vstavi stolpec pred", + "Insert column after": "Vstavi stolpec po", + "Delete column": "Izbriši stolpec", + "Cell": "Celica", + "Merge cells": "Združi celice", + "Horizontal split": "Horizontalni razcep", + "Vertical split": "Vertikalni razcep", + "Cell Background": "Ozadje celice", + "Vertical Align": "Vertikalna poravnava", + "Top": "Vrh", + "Middle": "Sredina", + "Bottom": "Dno", + "Align Top": "Vrhnja poravnava", + "Align Middle": "Sredinska poravnava", + "Align Bottom": "Spodnja poravnava", + "Cell Style": "Slog celice", + + // Files + "Upload File": "Naloži datoteko", + "Drop file": "Spustite datoteko sem", + + // Emoticons + "Emoticons": "Emotikoni", + + // Line breaker + "Break": "Prelom", + + // Math + "Subscript": "Podpisano", + "Superscript": "Nadpisano", + + // Full screen + "Fullscreen": "Celozaslonski način", + + // Horizontal line + "Insert Horizontal Line": "Vstavi vodoravno črto", + + // Clear formatting + "Clear Formatting": "Počisti oblikovanje", + + // Save + "Save": "Shrani", + + // Undo, redo + "Undo": "Razveljavi", + "Redo": "Ponovno uveljavi", + + // Select all + "Select All": "Izberi vse", + + // Code view + "Code View": "Pogled kode", + + // Quote + "Quote": "Citat", + "Increase": "Povečaj", + "Decrease": "Zmanjšaj", + + // Quick Insert + "Quick Insert": "Hitro vstavljanje", + + // Special Characters + "Special Characters": "Posebni znaki", + "Latin": "Latinica", + "Greek": "Grščina", + "Cyrillic": "Cirilica", + "Punctuation": "Ločila", + "Currency": "Valute", + "Arrows": "Puščice", + "Math": "Matematika", + "Misc": "Razno", + + // Print. + "Print": "Natisni", + + // Spell Checker. + "Spell Checker": "Črkovalnik", + + // Help + "Help": "Pomoč", + "Shortcuts": "Bližnjice", + "Inline Editor": "Vdelani urejevalnik", + "Show the editor": "Pokaži urejevalnik", + "Common actions": "Skupna dejanja", + "Copy": "Kopiraj", + "Cut": "Izreži", + "Paste": "Prilepi", + "Basic Formatting": "Osnovno oblikovanje", + "Increase quote level": "Povečaj raven citata", + "Decrease quote level": "Zmanjšaj raven citata", + "Image / Video": "Slika / Video", + "Resize larger": "Povečaj", + "Resize smaller": "Pomanjšaj", + "Table": "Tabela", + "Select table cell": "Izberi celico tabele", + "Extend selection one cell": "Razširi izbor za eno celico", + "Extend selection one row": "Razširi izbor za eno vrstico", + "Navigation": "Navigacija", + "Focus popup / toolbar": "Fokusiraj pojavno okno / orodno vrstico", + "Return focus to previous position": "Vrni fokus v prejšnji položaj", + + // Embed.ly + "Embed URL": "Vdelaj URL", + "Paste in a URL to embed": "Prilepite URL za vdelavo", + + // Word Paste. + "The pasted content is coming from a Microsoft Word document. Do you want to keep the format or clean it up?": "Prilepljena vsebina prihaja iz dokumenta Microsoft Word. Ali želite obliko obdržati ali jo želite očistiti?", + "Keep": "Obdrži", + "Clean": "Počisti", + "Word Paste Detected": "Zaznano je lepljenje s programa Word" + }, + direction: "ltr" +}; + +})); diff --git a/modules/backend/lang/sl/lang.php b/modules/backend/lang/sl/lang.php new file mode 100644 index 0000000000..9e2fa903ce --- /dev/null +++ b/modules/backend/lang/sl/lang.php @@ -0,0 +1,628 @@ + [ + 'title' => 'Nadzorna plošča', + 'invalid_login' => 'Podatki, ki ste jih vnesli, se ne ujemajo z našimi zapisi. Prosimo, ponovno preverite podatke in poskusite znova.', + ], + 'field' => [ + 'invalid_type' => 'Uporabljen je neveljaven tip polja :type.', + 'options_method_invalid_model' => "Atribut ':field' ne ustreza veljavnemu modelu. Poskusite natančno določiti možnosti metode za model :model.", + 'options_method_not_exists' => "Model :model mora vsebovati metodo :method(), ki vrača možnosti za polje ':field' na obrazcu.", + 'colors_method_not_exists' => "Model :model mora vsebovati metodo :method(), ki vrača HTML barvne kode v HEX formatu za polje ':field' na obrazcu.", + ], + 'widget' => [ + 'not_registered' => "Ime vtičnika ':name' ni bilo registrirano", + 'not_bound' => "Vtičnik z imenom ':name' ni vezan na kontroler", + ], + 'page' => [ + 'untitled' => 'Brez naslova', + '404' => [ + 'label' => 'Stran ne obstaja', + 'help' => 'Kljub intenzivnemu iskanju, zahtevanega URL-ja preprosto ni mogoče najti. Ste morda iskali kaj drugega?', + 'back_link' => 'Vrni se na prejšnjo stran', + ], + 'access_denied' => [ + 'label' => 'Dostop zavrnjen', + 'help' => 'Nimate potrebnih dovoljenj za ogled te strani.', + 'cms_link' => 'Vrni se v administracijo', + ], + 'no_database' => [ + 'label' => 'Podatkovna zbirka manjka', + 'help' => 'Za dostop do administracije je potrebna podatkovna zbirka. Preverite, če je podatkovna zbirka pravilno nastavljena in če so bile migracije pognane ter poskusite ponovno.', + 'cms_link' => 'Vrni se na domačo stran', + ], + ], + 'partial' => [ + 'not_found_name' => "Predloge ':name' ni mogoče najti.", + 'invalid_name' => 'Neveljavno ime predloge: :name.', + ], + 'ajax_handler' => [ + 'invalid_name' => 'Neveljavno ime AJAX akcije: :name.', + 'not_found' => "Ni mogoče najti AJAX akcije ':name'.", + ], + 'account' => [ + 'impersonate' => 'Oponašaj uporabnika', + 'impersonate_confirm' => 'Ali ste prepričani, da želite oponašati tega uporabnika? V prvotno stanje se lahko vrnete tako, da se odjavite.', + 'impersonate_success' => 'Sedaj oponašate tega uporabnika', + 'impersonate_working' => 'Oponašam...', + 'impersonating' => 'Oponašanje :full_name', + 'stop_impersonating' => 'Prekliči oponašanje', + 'signed_in_as' => 'Prijavljen kot :full_name', + 'sign_out' => 'Odjava', + 'login' => 'Prijava', + 'reset' => 'Ponastavi', + 'restore' => 'Obnovi', + 'login_placeholder' => 'uporabniško ime', + 'password_placeholder' => 'geslo', + 'remember_me' => 'Ostanite prijavljeni', + 'forgot_password' => 'Ste pozabili svoje geslo?', + 'enter_email' => 'Vnesite svoj e-poštni naslov', + 'enter_login' => 'Vnesite svoje uporabniško ime', + 'email_placeholder' => 'e-pošta', + 'enter_new_password' => 'Vnesite novo geslo', + 'password_reset' => 'Ponastavitev gesla', + 'restore_success' => 'Na vaš e-poštni naslov je bilo poslano sporočilo z navodili.', + 'restore_error' => "Uporabnika z uporabniškim imenom ':login' ni mogoče najti.", + 'reset_success' => 'Geslo je bilo ponastavljeno. Sedaj se lahko prijavite.', + 'reset_error' => 'Posredovani so bili neveljavni podatki za ponastavitev gesla. Prosimo, poskusite znova!', + 'reset_fail' => 'Gesla ni bilo mogoče ponastaviti!', + 'apply' => 'Sprejmi', + 'cancel' => 'Prekliči', + 'delete' => 'Izbriši', + 'ok' => 'OK', + ], + 'dashboard' => [ + 'menu_label' => 'Nadzorna plošča', + 'widget_label' => 'Vtičnik', + 'widget_width' => 'Širina', + 'full_width' => 'Celotna širina', + 'manage_widgets' => 'Upravljanje vtičnikov', + 'add_widget' => 'Dodaj vtičnik', + 'widget_inspector_title' => 'Nastavitve vtičnika', + 'widget_inspector_description' => 'Nastavitve prikaza vtičnika', + 'widget_columns_label' => 'Širina :columns', + 'widget_columns_description' => 'Širina vtičnika, število med 1 in 10.', + 'widget_columns_error' => 'Prosimo, vnesite širino vtičnika v obliki števila med 1 in 10.', + 'columns' => '{1} stolpec|{2} stolpca|[3,4] stolpci|[5,Inf] stolpcev', + 'widget_new_row_label' => 'Vsili novo vrstico', + 'widget_new_row_description' => 'Postavi vtičnik v novo vrstico', + 'widget_title_label' => 'Naslov vtičnika', + 'widget_title_error' => 'Potreben je vnos naslova vtičnika.', + 'reset_layout' => 'Ponastavi postavitev', + 'reset_layout_confirm' => 'Želite postavitev ponastaviti nazaj na privzeto obliko?', + 'reset_layout_success' => 'Postavitev je bila ponastavljena', + 'make_default' => 'Nastavi za privzeto', + 'make_default_confirm' => 'Želite trenutno postavitev nastaviti za privzeto?', + 'make_default_success' => 'Trenutna postavitev je nastavljena kot privzeta', + 'collapse_all' => 'Strni vse', + 'expand_all' => 'Razširi vse', + 'status' => [ + 'widget_title_default' => 'Status sistema', + 'update_available' => '[0,1] posodobitev na voljo!|{2} posodobitvi na voljo!|[3,4] posodobitve na voljo!|[5,Inf] posodobitev na voljo!', + 'updates_pending' => 'Posodobitev programske opreme je na voljo', + 'updates_nil' => 'Programska oprema je posodobljena', + 'updates_link' => 'Posodobi', + 'warnings_pending' => 'Nekatere težave potrebujejo vašo pozornost', + 'warnings_nil' => 'Ni opozoril za prikaz', + 'warnings_link' => 'Prikaži', + 'core_build' => 'Različica sistema', + 'event_log' => 'Dnevnik dogodkov', + 'request_log' => 'Dnevnik zahtev', + 'app_birthday' => 'Na spletu od', + ], + 'welcome' => [ + 'widget_title_default' => 'Dobrodošli!', + 'welcome_back_name' => 'Dobrodošli nazaj v :app, :name.', + 'welcome_to_name' => 'Dobrodošli v :app, :name.', + 'first_sign_in' => 'To je vaša prva prijava.', + 'last_sign_in' => 'Vaša zadnja prijava je zabeležena.', + 'view_access_logs' => 'Prikaži dnevnik prijav', + 'nice_message' => 'Imejte lep dan!', + ], + ], + 'user' => [ + 'name' => 'Administrator', + 'menu_label' => 'Administratorji', + 'menu_description' => 'Upravljanje z administratorji, skupinami in dovoljenji.', + 'list_title' => 'Upravljanje administratorjev', + 'new' => 'Nov administrator', + 'login' => 'Uporabniško ime', + 'first_name' => 'Ime', + 'last_name' => 'Priimek', + 'full_name' => 'Polno ime', + 'email' => 'E-poštni naslov', + 'role_field' => 'Vloga', + 'role_comment' => 'Vloge določajo uporabniška dovoljenja, ki jih je možno spremeniti na ravni uporabnika, na zavihku Dovoljenja.', + 'groups' => 'Skupine', + 'groups_comment' => 'Določite, katerim skupinam pripada ta uporabniški račun.', + 'avatar' => 'Avatar', + 'password' => 'Geslo', + 'password_confirmation' => 'Potrdite geslo', + 'permissions' => 'Dovoljenja', + 'account' => 'Uporabniški račun', + 'superuser' => 'Super administrator', + 'superuser_comment' => 'Temu uporabniškemu računu omogoča neomejen dostop do vseh področij sistema. Super administrator lahko dodaja in upravlja druge uporabnike.', + 'send_invite' => 'Pošlji vabilo po e-pošti', + 'send_invite_comment' => 'Pošlje pozdravno e-poštno sporočilo s podatki o uporabniškem imenu in geslu.', + 'delete_confirm' => 'Želite izbrisati tega administratorja?', + 'return' => 'Vrni se na seznam administratorjev', + 'allow' => 'Dovoli', + 'inherit' => 'Podeduj', + 'deny' => 'Ne dovoli', + 'activated' => 'Aktiviran', + 'last_login' => 'Zadnja prijava', + 'created_at' => 'Ustvarjen', + 'updated_at' => 'Posodobljen', + 'deleted_at' => 'Izbrisan', + 'show_deleted' => 'Prikaži izbrisane', + 'group' => [ + 'name' => 'Skupina', + 'name_field' => 'Ime', + 'name_comment' => 'Ime je prikazano na seznamu skupin na administratorskem obrazcu.', + 'description_field' => 'Opis', + 'is_new_user_default_field_label' => 'Privzeta skupina', + 'is_new_user_default_field_comment' => 'Nove administratorje vedno vključi v to skupino.', + 'code_field' => 'Koda', + 'code_comment' => 'Vnesite unikatno kodo, če želite dostopati do objekta skupine preko API klica.', + 'menu_label' => 'Upravljanje s skupinami', + 'list_title' => 'Upravljanje s skupinami', + 'new' => 'Nova skupina', + 'delete_confirm' => 'Želite odstraniti to administratorsko skupino?', + 'return' => 'Vrni se na seznam skupin', + 'users_count' => 'Uporabniki', + ], + 'role' => [ + 'name' => 'Vloga ', + 'name_field' => 'Ime', + 'name_comment' => 'Ime je prikazano na seznamu vlog na administratorskem obrazcu.', + 'description_field' => 'Opis', + 'code_field' => 'Koda', + 'code_comment' => 'Vnesite unikatno kodo, če želite dostopati do objekta vloge preko API klica.', + 'menu_label' => 'Upravljanje z vlogami', + 'list_title' => 'Upravljanje z vlogami', + 'new' => 'Nova vloga', + 'delete_confirm' => 'Želite odstraniti to administratorsko vlogo?', + 'return' => 'Vrni se na seznam vlog', + 'users_count' => 'Uporabniki', + ], + 'preferences' => [ + 'not_authenticated' => 'Ni overjenega uporabnika, za katerega bi lahko naložili ali shranili nastavitve.', + ], + 'trashed_hint_title' => 'Ta uporabniški račun je bil izbrisan', + 'trashed_hint_desc' => 'Ta uporabniški račun je bil izbrisan in prijava z njim ni več mogoča. Če ga želite obnoviti, kliknite ikono za obnovitev uporabnika v spodnjem desnem kotu', + ], + 'list' => [ + 'default_title' => 'Seznam', + 'search_prompt' => 'Iskanje...', + 'no_records' => 'Ni najdenih zapisov.', + 'missing_model' => 'Seznam, uporabljen v :class, nima definiranega modela.', + 'missing_column' => 'Manjkajo definicije stolpcev za stolpce :columns.', + 'missing_columns' => 'Seznam, uporabljen v :class, nima definiranih stolpcev seznama.', + 'missing_definition' => "Seznam ne vsebuje stolpca za ':field'.", + 'missing_parent_definition' => "Seznam ne vsebuje definicije za ':definition'.", + 'behavior_not_ready' => 'Seznam se ni inicializiral. Preverite, ali ste v kontrolerju poklicali metodo makeLists().', + 'invalid_column_datetime' => "Vrednost stolpca ':column' ni DateTime objekt. Preverite, ali imate v vašem Modelu definirano referenco \$dates.", + 'pagination' => 'Prikazani zapisi: :from-:to od :total', + 'first_page' => 'Prva stran', + 'last_page' => 'Zadnja stran', + 'prev_page' => 'Prejšnja stran', + 'next_page' => 'Naslednja stran', + 'refresh' => 'Osveži', + 'updating' => 'Posodabljanje...', + 'loading' => 'Nalaganje...', + 'setup_title' => 'Nastavitve seznama', + 'setup_help' => 'Izberite stolpce, ki jih želite prikazati na seznamu. Položaj stolpcev lahko spremenite tako, da jih povlečete gor ali dol.', + 'records_per_page' => 'Število zapisov na strani', + 'records_per_page_help' => 'Izberite koliko zapisov želite prikazati na eni strani. Upoštevajte, da lahko večje število zapisov na eni strani zmanjša hitrost delovanja.', + 'check' => 'Označi', + 'delete_selected' => 'Izbriši izbrano', + 'delete_selected_empty' => 'Ni izbranih zapisov za izbris.', + 'delete_selected_confirm' => 'Želite izbrisati izbrane zapise?', + 'delete_selected_success' => 'Izbrani zapisi so izbrisani.', + 'column_switch_true' => 'Da', + 'column_switch_false' => 'Ne', + ], + 'fileupload' => [ + 'attachment' => 'Priponka', + 'help' => 'Dodajte naslov in opis za to priponko.', + 'title_label' => 'Naslov', + 'description_label' => 'Opis', + 'default_prompt' => 'Če želite naložiti datoteko, kliknite %s ali povlecite datoteko v to polje', + 'attachment_url' => 'URL priloge', + 'upload_file' => 'Naloži datoteko', + 'upload_error' => 'Napaka pri nalaganju', + 'remove_confirm' => 'Ali ste prepričani?', + 'remove_file' => 'Odstrani datoteko', + ], + 'repeater' => [ + 'add_new_item' => 'Dodaj nov element', + 'min_items_failed' => ':name zahteva najmanj :min elementov, zagotovljenih je le :items elementov', + 'max_items_failed' => ':name dovoli največ :max elementov, :items elementov je bilo podanih', + ], + 'form' => [ + 'create_title' => 'Ustvari element ":name"', + 'update_title' => 'Uredi element ":name"', + 'preview_title' => 'Predogled elementa ":name"', + 'create_success' => 'Element ":name" je ustvarjen', + 'update_success' => 'Element ":name" je posodobljen', + 'delete_success' => 'Element ":name" je izbrisan', + 'restore_success' => 'Element ":name" je obnovljen', + 'reset_success' => 'Ponastavitev je zaključena', + 'missing_id' => 'ID obrazca ni bil določen.', + 'missing_model' => 'Obrazec, uporabljen v :class, nima definiranega modela.', + 'missing_definition' => "Obrazec ne vsebuje stolpca za ':field'.", + 'not_found' => 'Obrazca z ID-jem :id ni mogoče najti.', + 'action_confirm' => 'Ali ste prepričani?', + 'create' => 'Ustvari', + 'create_and_close' => 'Ustvari in zapri', + 'creating' => 'Ustvarjanje...', + 'creating_name' => 'Ustvarjanje :name...', + 'save' => 'Shrani', + 'save_and_close' => 'Shrani in zapri', + 'saving' => 'Shranjevanje...', + 'saving_name' => 'Shranjevanje :name...', + 'delete' => 'Izbriši', + 'deleting' => 'Brisanje...', + 'confirm_delete' => 'Želite izbrisati zapis?', + 'confirm_delete_multiple' => 'Želite izbrisati izbrane zapise?', + 'deleting_name' => 'Brisanje :name...', + 'restore' => 'Obnovi', + 'restoring' => 'Obnavljanje', + 'confirm_restore' => 'Ali ste prepričani, da želite obnoviti ta zapis?', + 'reset_default' => 'Ponastavi na privzeto', + 'resetting' => 'Ponastavljanje', + 'resetting_name' => 'Ponastavljanje :name', + 'undefined_tab' => 'Razno', + 'field_off' => 'Ne', + 'field_on' => 'Da', + 'add' => 'Dodaj', + 'apply' => 'Uporabi', + 'cancel' => 'Prekliči', + 'close' => 'Zapri', + 'confirm' => 'Potrdi', + 'reload' => 'Ponovno naloži', + 'complete' => 'Zaključi', + 'ok' => 'OK', + 'or' => 'ali', + 'confirm_tab_close' => 'Zaprem zavihek? Neshranjene spremembe bodo izgubljene.', + 'behavior_not_ready' => 'Obrazec se ni inicializiral. Preverite, ali ste v kontrolerju poklicali metodo initForm().', + 'preview_no_files_message' => 'Ni naloženih datotek.', + 'preview_no_media_message' => 'Ni izbranih media datotek.', + 'preview_no_record_message' => 'Ni izbranih zapisov.', + 'select' => 'Izberi', + 'select_all' => 'vse', + 'select_none' => 'nobenega', + 'select_placeholder' => 'izberite', + 'insert_row' => 'Vstavi vrstico', + 'insert_row_below' => 'Vstavi vrstico spodaj', + 'delete_row' => 'Izbriši vrstico', + 'concurrency_file_changed_title' => 'Datoteka je bila spremenjena', + 'concurrency_file_changed_description' => 'Datoteka, ki jo urejate, je bila spremenjena s strani drugega uporabnika. Datoteko lahko znova naložite in izgubite vaše spremembe ali pa jo prepišete s svojimi spremembami.', + 'return_to_list' => 'Vrni se na seznam', + ], + 'recordfinder' => [ + 'find_record' => 'Poišči zapis', + 'invalid_model_class' => 'Model ":modelClass", podan za iskalnik zapisov, je neveljaven', + 'cancel' => 'Prekliči', + ], + 'pagelist' => [ + 'page_link' => 'Povezava do strani', + 'select_page' => 'Izberite stran...', + ], + 'relation' => [ + 'missing_config' => "Relacija ne vsebuje nastavitev za ':config'.", + 'missing_definition' => "Relacija ne vsebuje definicije za ':field'.", + 'missing_model' => 'Relacija, uporabljena v :class, nima definiranega modela.', + 'invalid_action_single' => 'Tega dejanja ni mogoče izvesti na relaciji ena proti ena.', + 'invalid_action_multi' => 'Tega dejanja ni mogoče izvesti na relaciji mnogo proti mnogo.', + 'help' => 'Kliknite na element, ki ga želite dodati', + 'related_data' => 'Povezani podatki :name', + 'add' => 'Dodaj', + 'add_selected' => 'Dodaj izbrano', + 'add_a_new' => 'Dodaj novo :name', + 'link_selected' => 'Povezava je izbrana', + 'link_a_new' => 'Poveži novo :name', + 'cancel' => 'Prekliči', + 'close' => 'Zapri', + 'add_name' => 'Dodaj :name', + 'create' => 'Ustvari', + 'create_name' => 'Ustvari :name', + 'update' => 'Posodobi', + 'update_name' => 'Posodobi :name', + 'preview' => 'Predogled', + 'preview_name' => 'Predogled za :name', + 'remove' => 'Odstrani', + 'remove_name' => 'Odstrani :name', + 'delete' => 'Izbriši', + 'delete_name' => 'Izbriši :name', + 'delete_confirm' => 'Ali ste prepričani?', + 'link' => 'Povezava', + 'link_name' => 'Povezava za :name', + 'unlink' => 'Odstrani povezavo', + 'unlink_name' => 'Odstrani povezavo :name', + 'unlink_confirm' => 'Ali ste prepričani?', + ], + 'reorder' => [ + 'default_title' => 'Razvrsti zapise', + 'no_records' => 'Na voljo ni nobenih zapisov za razvrščanje.', + ], + 'model' => [ + 'name' => 'Model', + 'not_found' => "Modela ':class' z ID-jem :id ni mogoče najti", + 'missing_id' => 'Za iskanje modela ni določen noben ID.', + 'missing_relation' => "Model ':class' nima definirane relacije ':relation'.", + 'missing_method' => "Model ':class' ne vsebuje metode ':method'.", + 'invalid_class' => "Model :model, uporabljen v :class ni veljaven. Dedovati mora objekt \Model.", + 'mass_assignment_failed' => "Masovna dodelitev je bila neuspešna za atribut ':attribute' na modelu.", + ], + 'warnings' => [ + 'tips' => 'Nasveti glede nastavitev sistema', + 'tips_description' => 'Za pravilno nastavitev sistema morate biti pozorni na določene podrobnosti.', + 'permissions' => 'PHP ne more pisati v mapo :name in njene podmape. Prosimo, nastavite spletnemu strežniku ustrezna dovoljenja za to mapo.', + 'extension' => 'PHP razširitev (extension) :name ni nameščena. Prosimo, namestite ustrezno knjižnico in aktivirajte razširitev.', + 'plugin_missing' => 'Za delovanje je potreben vtičnik :name, vendar ni nameščen. Prosimo, namestite ta vtičnik.', + 'debug' => 'Način za odpravljanje napak je omogočen. Ta način ni priporočljiv za produkcijsko okolje.', + 'decompileBackendAssets' => 'Oblikovne datoteke (CSS, JavaSrcipt) v administraciji so trenutno nestisnjene. To ni priporočljivo za produkcijsko okolje.', + ], + 'editor' => [ + 'menu_label' => 'Nastavitve urejevalnika', + 'menu_description' => 'Splošne nastavitve urejevalnika, kot npr. velikost pisave in barvna shema.', + 'font_size' => 'Velikost pisave', + 'tab_size' => 'Širina tabulatorja', + 'use_hard_tabs' => 'Odmik s tabulatorjem', + 'code_folding' => 'Strnjevanje kode', + 'code_folding_begin' => 'Označi začetek', + 'code_folding_begin_end' => 'Označi začetek in konec', + 'autocompletion' => 'Samodejno dokončanje', + 'word_wrap' => 'Prelom besed', + 'highlight_active_line' => 'Označi aktivno vrstico', + 'auto_closing' => 'Samodejno zapri označbe', + 'show_invisibles' => 'Prikaži nevidne znake', + 'show_gutter' => 'Prikaži odmike', + 'basic_autocompletion' => 'Osnovno samodejno dokončanje (Ctrl + Space)', + 'live_autocompletion' => 'Instantno samodejno dokončanje', + 'enable_snippets' => 'Omogoči odseke kode (Tab)', + 'display_indent_guides' => 'Prikaži vodila za odmike', + 'show_print_margin' => 'Prikaži rob tiskanja', + 'mode_off' => 'Izključi', + 'mode_fluid' => 'Fluidno', + '40_characters' => '40 znakov', + '80_characters' => '80 znakov', + 'theme' => 'Barvna shema', + 'markup_styles' => 'Označevalni slogi', + 'custom_styles' => 'Slog po meri', + 'custom styles_comment' => 'Slogi, ki jih želite vključiti v urejevalnik HTML.', + 'markup_classes' => 'Označevalni razredi', + 'paragraph' => 'Odstavek', + 'link' => 'Povezava', + 'table' => 'Tabela', + 'table_cell' => 'Celica tabele', + 'image' => 'Slika', + 'label' => 'Opis', + 'class_name' => 'Oznaka razreda', + 'markup_tags' => 'Označevalne oznake', + 'allowed_empty_tags' => 'Dovoljene prazne oznake', + 'allowed_empty_tags_comment' => 'Seznam oznak, ki niso odstranjene, če v njih ni vsebine.', + 'allowed_tags' => 'Dovoljene oznake', + 'allowed_tags_comment' => 'Seznam dovoljenih oznak.', + 'no_wrap' => 'Nezavite oznake', + 'no_wrap_comment' => 'Seznam oznak, ki naj ne bodo zavite znotraj blokovskih oznak.', + 'remove_tags' => 'Odstrani oznake', + 'remove_tags_comment' => 'Seznam oznak, ki so odstranjene skupaj z njihovo vsebino.', + 'line_breaker_tags' => 'Oznake prekinitve vrstic', + 'line_breaker_tags_comment' => 'Seznam oznak, ki se uporabljajo za postavitev elementa prekinitve med vrstice.', + 'toolbar_buttons' => 'Gumbi orodne vrstice', + 'toolbar_buttons_comment' => 'Gumbi orodne vrstice, ki se privzeto prikažejo v urejevalniku. [fullscreen, bold, italic, underline, strikeThrough, subscript, superscript, fontFamily, fontSize, |, color, emoticons, inlineStyle, paragraphStyle, |, paragraphFormat, align, formatOL, formatUL, outdent, indent, quote, insertHR, -, insertLink, insertImage, insertVideo, insertAudio, insertFile, insertTable, undo, redo, clearFormatting, selectAll, html]', + ], + 'tooltips' => [ + 'preview_website' => 'Ogled spletne strani', + ], + 'mysettings' => [ + 'menu_label' => 'Moje nastavitve', + 'menu_description' => 'Nastavitve, povezane z vašim administratorskim računom', + ], + 'myaccount' => [ + 'menu_label' => 'Moj profil', + 'menu_description' => 'Urejanje podatkov vašega profila, kot so ime, e-pošta in geslo.', + 'menu_keywords' => 'varnostna prijava', + ], + 'branding' => [ + 'menu_label' => 'Prilagoditev administracije', + 'menu_description' => 'Prilagoditev okolja administracije, kot so npr. ime, barve in logotip.', + 'brand' => 'Splošno', + 'logo' => 'Logo', + 'logo_description' => 'Naložite poljuben logotip, ki ga želite prikazati v administraciji.', + 'favicon' => 'Ikona zaznamka (favicon)', + 'favicon_description' => 'Naložite poljubno ikono zaznamka administracijo.', + 'app_name' => 'Ime aplikacije', + 'app_name_description' => 'Ime je prikazano v naslovni vrstici administracije.', + 'app_tagline' => 'Slogan aplikacije', + 'app_tagline_description' => 'Slogan je prikazan na prijavnem oknu administracije.', + 'colors' => 'Barve', + 'primary_color' => 'Primarna barva', + 'secondary_color' => 'Sekundarna barva', + 'accent_color' => 'Poudarjena barva', + 'styles' => 'CSS slogi', + 'custom_stylesheet' => 'CSS slogi po meri', + 'navigation' => 'Navigacija', + 'menu_mode' => 'Slog menija', + 'menu_mode_inline' => 'Vrstični', + 'menu_mode_inline_no_icons' => 'Vrstični (brez ikon)', + 'menu_mode_tile' => 'Ploščice', + 'menu_mode_collapsed' => 'Strnjen', + ], + 'backend_preferences' => [ + 'menu_label' => 'Nastavitve administracije', + 'menu_description' => 'Upravljajte nastavitve vašega profila, kot je npr. jezik.', + 'region' => 'Regija', + 'code_editor' => 'Urejevalnik kode', + 'timezone' => 'Časovni pas', + 'timezone_comment' => 'Prikazani datumi se prilagodijo glede na izbran časovni pas.', + 'locale' => 'Jezik', + 'locale_comment' => 'Izberite želeni jezik za uporabo v administraciji.', + ], + 'access_log' => [ + 'hint' => 'Ta dnevnik beleži seznam uspešnih prijav administratorjev. Zapisi se hranijo :days dni.', + 'menu_label' => 'Dnevnik dostopa', + 'menu_description' => 'Prikaz seznama uspešnih prijav administratorjev.', + 'id' => 'ID', + 'created_at' => 'Datum in čas', + 'type' => 'Tip', + 'login' => 'Uporabniško ime', + 'ip_address' => 'IP naslov', + 'first_name' => 'Ime', + 'last_name' => 'Priimek', + 'email' => 'E-pošta', + ], + 'filter' => [ + 'all' => 'vsi', + 'options_method_not_exists' => "Model :model mora vsebovati metodo :method(), ki vrača možnosti za filter ':filter'.", + 'date_all' => 'vse periode', + 'number_all' => 'vsa števila', + ], + 'import_export' => [ + 'upload_csv_file' => '1. Naložite CSV datoteko', + 'import_file' => 'Uvozi datoteko', + 'row' => 'Vrstica :row', + 'first_row_contains_titles' => 'Prva vrstica vsebuje naslove stolpcev', + 'first_row_contains_titles_desc' => 'To polje pustite označeno, če prva vrstica v vaši CSV datoteki vsebuje naslove stolpcev.', + 'match_columns' => '2. Povežite stolce v datoteki s polji v podatkovni zbirki', + 'file_columns' => 'Stolpci v datoteki', + 'database_fields' => 'Polja v podatkovni zbirki', + 'set_import_options' => '3. Nastavite možnosti uvoza', + 'export_output_format' => '1. Izberite format izvozne datoteke', + 'file_format' => 'Format datoteke', + 'standard_format' => 'Standardni format', + 'custom_format' => 'Format po meri', + 'delimiter_char' => 'Znak ločila', + 'enclosure_char' => 'Znak zaključka', + 'escape_char' => 'Izhodni znak', + 'select_columns' => '2. Označite stolpce za izvoz', + 'column' => 'Stolpec', + 'columns' => 'Stolpci', + 'set_export_options' => '3. Nastavitve možnosti izvoza', + 'show_ignored_columns' => 'Prikaži prezrte stolpce', + 'auto_match_columns' => 'Samodejno poveži stolpce', + 'created' => 'Ustvarjeno', + 'updated' => 'Posodobljeno', + 'skipped' => 'Izpuščeno', + 'warnings' => 'Opozorila', + 'errors' => 'Napake', + 'skipped_rows' => 'Izpuščene vrstice', + 'import_progress' => 'Napredek uvoza', + 'processing' => 'Procesiranje', + 'import_error' => 'Napaka pri uvozu', + 'upload_valid_csv' => 'Prosimo, naložite veljavno CSV datoteko.', + 'drop_column_here' => 'Spustite stolpec sem...', + 'ignore_this_column' => 'Prezri ta stolpec', + 'processing_successful_line1' => 'Izvoz datoteke je zaključen!', + 'processing_successful_line2' => 'Brskalnik vas bo sedaj preusmeril na prenos datoteke.', + 'export_progress' => 'Napredek izvoza', + 'export_error' => 'Napaka pri izvozu', + 'column_preview' => 'Predogled stolpca', + 'file_not_found_error' => 'Datoteke ni mogoče najti', + 'empty_error' => 'Ni podanih podatkov za izvoz', + 'empty_import_columns_error' => 'Prosimo, določite nekaj stolpcev za uvoz.', + 'match_some_column_error' => 'Prosimo, najprej povežite nekaj stolpcev.', + 'required_match_column_error' => 'Prosimo, določite povezavo za zahtevano polje :label.', + 'empty_export_columns_error' => 'Prosimo, določite nekaj stolpcev za izvoz.', + 'behavior_missing_uselist_error' => 'Implementirati morate kontroler ListController z omogočeno možnostjo izvoza "useList".', + 'missing_model_class_error' => 'Prosimo, določite modelClass lastnost za :type', + 'missing_column_id_error' => 'Manjka identifikator stolpca', + 'unknown_column_error' => 'Neznan stolpec', + 'encoding_not_supported_error' => 'Kodiranje izvorne datoteke ni prepoznano. Za uspešen uvoz vaše datoteke izberite ustrezno kodiranje.', + 'encoding_format' => 'Kodiranje datoteke', + 'encodings' => [ + 'utf_8' => 'UTF-8', + 'us_ascii' => 'US-ASCII', + 'iso_8859_1' => 'ISO-8859-1 (Latin-1, Western European)', + 'iso_8859_2' => 'ISO-8859-2 (Latin-2, Central European)', + 'iso_8859_3' => 'ISO-8859-3 (Latin-3, South European)', + 'iso_8859_4' => 'ISO-8859-4 (Latin-4, North European)', + 'iso_8859_5' => 'ISO-8859-5 (Latin, Cyrillic)', + 'iso_8859_6' => 'ISO-8859-6 (Latin, Arabic)', + 'iso_8859_7' => 'ISO-8859-7 (Latin, Greek)', + 'iso_8859_8' => 'ISO-8859-8 (Latin, Hebrew)', + 'iso_8859_0' => 'ISO-8859-9 (Latin-5, Turkish)', + 'iso_8859_10' => 'ISO-8859-10 (Latin-6, Nordic)', + 'iso_8859_11' => 'ISO-8859-11 (Latin, Thai)', + 'iso_8859_13' => 'ISO-8859-13 (Latin-7, Baltic Rim)', + 'iso_8859_14' => 'ISO-8859-14 (Latin-8, Celtic)', + 'iso_8859_15' => 'ISO-8859-15 (Latin-9, Western European revision with euro sign)', + 'windows_1251' => 'Windows-1251 (CP1251)', + 'windows_1252' => 'Windows-1252 (CP1252)' + ] + ], + 'permissions' => [ + 'manage_media' => 'Nalaganje in upravljanje z media vsebinami - slike, video posnetki, zvočni posnetki, dokumenti', + ], + 'mediafinder' => [ + 'label' => 'Media brskalnik', + 'default_prompt' => 'Kliknite gumb %s za iskanje media elementa', + 'no_image' => 'Slike ni mogoče najti', + ], + 'media' => [ + 'menu_label' => 'Media', + 'upload' => 'Naloži', + 'move' => 'Premakni', + 'delete' => 'Izbriši', + 'add_folder' => 'Dodaj mapo', + 'search' => 'Iskanje', + 'display' => 'Prikaz', + 'filter_everything' => 'Vse', + 'filter_images' => 'Slike', + 'filter_video' => 'Video', + 'filter_audio' => 'Audio', + 'filter_documents' => 'Dokumenti', + 'library' => 'Knjižnica', + 'size' => 'Velikost', + 'title' => 'Naslov', + 'last_modified' => 'Zadnja sprememba', + 'public_url' => 'URL', + 'click_here' => 'Kliknite tukaj', + 'thumbnail_error' => 'Napaka pri ustvarjanju sličice.', + 'return_to_parent' => 'Vrni se v nadrejeno mapo', + 'return_to_parent_label' => 'Pojdi gor ..', + 'nothing_selected' => 'Nič ni izbrano.', + 'multiple_selected' => 'Izbranih je več elementov.', + 'uploading_file_num' => 'Nalaganje :number datotek(e)...', + 'uploading_complete' => 'Nalaganje zaključeno', + 'uploading_error' => 'Nalaganje ni uspelo', + 'type_blocked' => 'Izbrani tip datoteke je blokiran iz varnostnih razlogov.', + 'order_by' => 'Razvrsti po', + 'direction' => 'Smer', + 'direction_asc' => 'Naraščajoče', + 'direction_desc' => 'Padajoče', + 'folder' => 'Mapa', + 'no_files_found' => 'Vaše iskanje se ne ujema z nobeno datoteko.', + 'delete_empty' => 'Prosimo, izberite elemente, ki jih želite izbrisati.', + 'delete_confirm' => 'Želite izbrisati izbrane elemente?', + 'error_renaming_file' => 'Napaka pri preimenovanju elementa.', + 'new_folder_title' => 'Nova mapa', + 'folder_name' => 'Ime mape', + 'error_creating_folder' => 'Napaka pri ustvarjanju mape', + 'folder_or_file_exist' => 'Datoteka ali mapa z izbranim imenom že obstaja.', + 'move_empty' => 'Prosimo, izberite elemente, ki jih želite premakniti.', + 'move_popup_title' => 'Premakni datoteke ali mape', + 'move_destination' => 'Ciljna mapa', + 'please_select_move_dest' => 'Prosimo, izberite ciljno mapo.', + 'move_dest_src_match' => 'Prosimo, izberite drugo ciljno mapo.', + 'empty_library' => 'Tukaj izgleda malo prazno. Za začetek naložite datoteke ali ustvarite mape.', + 'insert' => 'Vstavi', + 'crop_and_insert' => 'Obreži in vstavi', + 'select_single_image' => 'Prosimo, izberite samo eno sliko.', + 'selection_not_image' => 'Izbrani element ni slika.', + 'restore' => 'Razveljavi vse spremembe', + 'resize' => 'Spremeni velikost...', + 'selection_mode_normal' => 'Normalno', + 'selection_mode_fixed_ratio' => 'Fiksno razmerje', + 'selection_mode_fixed_size' => 'Fiksna velikost', + 'height' => 'Višina', + 'width' => 'Širina', + 'selection_mode' => 'Izbirni način', + 'resize_image' => 'Spremeni velikost slike', + 'image_size' => 'Velikost slike:', + 'selected_size' => 'Izbrano:', + ], +]; diff --git a/modules/backend/models/Preference.php b/modules/backend/models/Preference.php index 18044180b1..12d7f0ae4a 100644 --- a/modules/backend/models/Preference.php +++ b/modules/backend/models/Preference.php @@ -212,6 +212,7 @@ public function getLocaleOptions() 'ro' => [Lang::get('system::lang.locale.ro'), 'flag-ro'], 'ru' => [Lang::get('system::lang.locale.ru'), 'flag-ru'], 'sk' => [Lang::get('system::lang.locale.sk'), 'flag-sk'], + 'sl' => [Lang::get('system::lang.locale.sl'), 'flag-si'], 'sv' => [Lang::get('system::lang.locale.sv'), 'flag-se'], 'th' => [Lang::get('system::lang.locale.th'), 'flag-th'], 'tr' => [Lang::get('system::lang.locale.tr'), 'flag-tr'], diff --git a/modules/cms/lang/sl/lang.php b/modules/cms/lang/sl/lang.php new file mode 100644 index 0000000000..a46cbbce04 --- /dev/null +++ b/modules/cms/lang/sl/lang.php @@ -0,0 +1,301 @@ + [ + 'invalid_file' => 'Neveljavno ime datoteke :name. Imena datotek lahko vsebujejo le alfanumerične simbole, podčrtaje, pomišljaje in pike. Nekaj primerov pravilnih imen datotek: page.htm, page, subdirectory/page', + 'invalid_property' => "Lastnost ':name' ne more biti nastavljena", + 'file_already_exists' => "Datoteka ':name' že obstaja", + 'error_saving' => "Napaka pri shranjevanju datoteke ':name'. Prosimo, preverite vaša uporabniška dovoljenja.", + 'error_creating_directory' => 'Napaka pri ustvarjanju mape :name. Prosimo, preverite vaša uporabniška dovoljenja.', + 'invalid_file_extension' => "Neveljaven format datoteke :invalid'. Veljavni formati so :allowed.", + 'error_deleting' => "Napaka pri brisanju predloge ':name'. Prosimo, preverite vaša uporabniška dovoljenja.", + 'delete_success' => 'Izbrisanih predlog: :count.', + 'file_name_required' => 'Obvezno polje: Ime datoteke', + 'safe_mode_enabled' => 'Varnostni način je trenutno vključen.', + ], + 'dashboard' => [ + 'active_theme' => [ + 'widget_title_default' => 'Spletna stran', + 'online' => 'Aktivna', + 'maintenance' => 'V vzdrževanju', + 'manage_themes' => 'Upravljaj teme', + 'customize_theme' => 'Prilagodi temo', + ], + ], + 'theme' => [ + 'not_found_name' => "Teme ':name' ni bilo mogoče najti.", + 'by_author' => 'Od :name', + 'active' => [ + 'not_set' => 'Aktivna tema ni nastavljena.', + 'not_found' => 'Aktivne teme ni mogoče najti.', + ], + 'edit' => [ + 'not_set' => 'Urejana tema ni nastavljena.', + 'not_found' => 'Urejane teme ni mogoče najti.', + 'not_match' => "Objekt, do katerega poskušate dostopati, ne pripada urejani temi. Prosimo, osvežite stran.", + ], + 'settings_menu' => 'Tema spletne strani', + 'settings_menu_description' => 'Upravljanje s temo spletne strani in možnostmi prilagoditve.', + 'default_tab' => 'Lastnosti', + 'name_label' => 'Ime', + 'name_create_placeholder' => 'Novo ime teme', + 'author_label' => 'Avtor', + 'author_placeholder' => 'Oseba ali ime podjetja', + 'description_label' => 'Opis', + 'description_placeholder' => 'Opis teme', + 'homepage_label' => 'Spletna stran', + 'homepage_placeholder' => 'URL spletne strani', + 'code_label' => 'Koda', + 'code_placeholder' => 'Unikatna koda teme, ki se uporablja za distribucijo', + 'preview_image_label' => 'Slika za predogled', + 'preview_image_placeholder' => 'Lokacija slike za predogled teme.', + 'dir_name_label' => 'Ime mape', + 'dir_name_create_label' => 'Ciljna mapa teme', + 'theme_label' => 'Tema', + 'theme_title' => 'Teme', + 'activate_button' => 'Aktiviraj', + 'active_button' => 'Aktiviraj', + 'customize_theme' => 'Prilagodi temo', + 'customize_button' => 'Prilagodi', + 'duplicate_button' => 'Podvoji', + 'duplicate_title' => 'Podvoji temo', + 'duplicate_theme_success' => 'Tema podvojena!', + 'manage_button' => 'Upravljanje', + 'manage_title' => 'Upravljanje s temo', + 'edit_properties_title' => 'Tema', + 'edit_properties_button' => 'Uredi lastnosti', + 'save_properties' => 'Shrani lastnosti', + 'import_button' => 'Uvozi', + 'import_title' => 'Uvozi temo', + 'import_theme_success' => 'Tema uvožena!', + 'import_uploaded_file' => 'Datoteka z arhivom teme', + 'import_overwrite_label' => 'Prepiši obstoječe datoteke', + 'import_overwrite_comment' => 'Odkljukajte to polje, če želite uvoziti le nove datoteke', + 'import_folders_label' => 'Mape', + 'import_folders_comment' => 'Prosimo, izberite mape tem, ki jih želite uvoziti', + 'export_button' => 'Izvozi', + 'export_title' => 'Izvozi temo', + 'export_folders_label' => 'Mape', + 'export_folders_comment' => 'Prosimo, izberite mape tem, ki jih želite izvoziti', + 'delete_button' => 'Izbriši', + 'delete_confirm' => 'Želite izbrisati to temo? Ukaza ni mogoče razveljaviti!', + 'delete_active_theme_failed' => 'Aktivne teme ni mogoče izbrisati. Najprej je potrebno zamenjati aktivno temo.', + 'delete_theme_success' => 'Tema izbrisana!', + 'create_title' => 'Ustvari temo', + 'create_button' => 'Ustvari', + 'create_new_blank_theme' => 'Ustvari novo prazno temo', + 'create_theme_success' => 'Tema ustvarjena!', + 'create_theme_required_name' => 'Prosimo, navedite ime teme.', + 'new_directory_name_label' => 'Mapa za temo', + 'new_directory_name_comment' => 'Podajte novo ime mape za podvojeno temo.', + 'dir_name_invalid' => 'Ime lahko vsebuje samo številke, latinične črke in naslednje simbole: _-', + 'dir_name_taken' => 'Želena mapa za temo že obstaja.', + 'find_more_themes' => 'Poišči več tem', + 'saving' => 'Shranjevanje teme...', + 'return' => 'Nazaj na seznam tem', + ], + 'maintenance' => [ + 'settings_menu' => 'Način vzdrževanja', + 'settings_menu_description' => 'Nastavitve načina vzdrževanja in preklop na način vzdrževanja.', + 'is_enabled' => 'Omogoči način vzdrževanja', + 'is_enabled_comment' => 'Izberite stran, ki bo prikazana ob vključenem načinu vzdrževanja.', + 'hint' => 'V načinu vzdrževanja bo stran o vzdrževanju prikazana obiskovalcem, ki niso prijavljeni v administracijo.', + ], + 'page' => [ + 'not_found_name' => "Strani ':name' ni mogoče najti.", + 'not_found' => [ + 'label' => 'Stran ne obstaja', + 'help' => 'Zahtevane strani ni bilo mogoče najti.', + ], + 'custom_error' => [ + 'label' => 'Napaka strani', + 'help' => 'Žal je šlo nekaj narobe in strani ni mogoče prikazati.', + ], + 'menu_label' => 'Strani', + 'unsaved_label' => 'Neshranjene strani', + 'no_list_records' => 'Ni najdenih strani.', + 'new' => 'Nova stran', + 'invalid_url' => 'Neveljavna oblika URL formata. URL se mora začeti z znakom za desno poševnico in lahko vsebuje številke, latinične črke in naslednje znake: ._-[]:?|/+*^$', + 'delete_confirm_multiple' => 'Želite izbrisati izbrane strani?', + 'delete_confirm_single' => 'Želite izbrisati to stran?', + 'no_layout' => '-- brez postavitve --', + 'cms_page' => 'CMS stran', + 'title' => 'Naslov strani', + 'url' => 'URL strani', + 'file_name' => 'Ime datoteke strani', + ], + 'layout' => [ + 'not_found_name' => "Postavitve ':name' ni mogoče najti.", + 'menu_label' => 'Postavitve', + 'unsaved_label' => 'Neshranjene postavitve', + 'no_list_records' => 'Ni najdenih postavitev.', + 'new' => 'Nova postavitev', + 'delete_confirm_multiple' => 'Želite izbrisati izbrane postavitve?', + 'delete_confirm_single' => 'Želite izbrisati to postavitev?', + ], + 'partial' => [ + 'not_found_name' => "Predloge ':name' ni mogoče najti.", + 'invalid_name' => 'Neveljavno ime predloge :name.', + 'menu_label' => 'Predloge', + 'unsaved_label' => 'Neshranjene predloge', + 'no_list_records' => 'Ni najdenih predlog.', + 'delete_confirm_multiple' => 'Želite izbrisati izbrane predloge?', + 'delete_confirm_single' => 'Želite izbrisati to predlogo?', + 'new' => 'Nova predloga', + ], + 'content' => [ + 'not_found_name' => "Datoteke z vsebino ':name' ni mogoče najti.", + 'menu_label' => 'Vsebine', + 'unsaved_label' => 'Neshranjena vsebina', + 'no_list_records' => 'Ni najdenih datotek z vsebino.', + 'delete_confirm_multiple' => 'Ali želite izbrisati izbrane datoteke ali mape z vsebino?', + 'delete_confirm_single' => 'Želite izbrisati to datoteko z vsebino?', + 'new' => 'Nova datoteka z vsebino', + ], + 'ajax_handler' => [ + 'invalid_name' => 'Neveljavno ime AJAX akcije: :name.', + 'not_found' => "Ni mogoče najti AJAX akcije ':name'.", + ], + 'cms' => [ + 'menu_label' => 'CMS' + ], + 'sidebar' => [ + 'add' => 'Dodaj', + 'search' => 'Iskanje...', + ], + 'editor' => [ + 'settings' => 'Nastavitve', + 'title' => 'Naslov', + 'new_title' => 'Nov naslov strani', + 'url' => 'URL', + 'filename' => 'Ime datoteke', + 'layout' => 'Postavitev', + 'description' => 'Opis', + 'preview' => 'Predogled', + 'meta' => 'Meta podatki', + 'meta_title' => 'Meta naslov', + 'meta_description' => 'Meta opis', + 'markup' => 'Označevalni jezik', + 'code' => 'Koda', + 'content' => 'Vsebina', + 'hidden' => 'Skrito', + 'hidden_comment' => 'Skrite strani so dostopne le uporabnikom, ki so prijavljeni v administracijo.', + 'enter_fullscreen' => 'Celozaslonski način', + 'exit_fullscreen' => 'Zapri celozaslonski način', + 'open_searchbox' => 'Odpri iskalnik', + 'close_searchbox' => 'Zapri iskalnik', + 'open_replacebox' => 'Odpri "Najdi in zamenjaj"', + 'close_replacebox' => 'Zapri "Najdi in zamenjaj"', + 'commit' => 'Shrani spremembe', + 'reset' => 'Ponastavi', + 'commit_confirm' => 'Ali ste prepričani, da želite shraniti spremembe datoteke v datotečni sistem? To bo prepisalo obstoječo datoteko v datotečnem sistemu', + 'reset_confirm' => 'Ali ste prepričani, da želite datoteko ponastaviti na kopijo, ki se nahaja v datotečnem sistemu? To bo datoteko v celoti nadomestilo z datoteko, ki se nahaja v datotečnem sistemu', + 'committing' => 'Shranjujem spremembe', + 'resetting' => 'Ponastavljam', + 'commit_success' => 'Sprememba :type je bila shranjena v datotečni sistem', + 'reset_success' => 'Sprememba :type je bila ponastavljena na različico iz datotečnega sistema', + ], + 'asset' => [ + 'menu_label' => 'Oblikovne datoteke', + 'unsaved_label' => 'Neshranjene datoteke', + 'drop_down_add_title' => 'Dodaj...', + 'drop_down_operation_title' => 'Dejanje...', + 'upload_files' => 'Naloži datoteke', + 'create_file' => 'Ustvari datoteko', + 'create_directory' => 'Ustvari mapo', + 'directory_popup_title' => 'Nova mapa', + 'directory_name' => 'Ime mape', + 'rename' => 'Preimenuj', + 'delete' => 'Izbriši', + 'move' => 'Premakni', + 'select' => 'Izberi', + 'new' => 'Nova datoteka', + 'rename_popup_title' => 'Preimenuj', + 'rename_new_name' => 'Novo ime', + 'invalid_path' => 'Lokacija lahko vsebuje le številke, latinične črke, presledke in naslednje znake: ._-/', + 'error_deleting_file' => 'Napaka pri brisanju datoteke :name.', + 'error_deleting_dir_not_empty' => 'Napaka pri brisanju mape :name. Mapa ni prazna.', + 'error_deleting_dir' => 'Napaka pri brisanju mape :name.', + 'invalid_name' => 'Ime lahko vsebuje le številke, latinične črke, presledke in naslednje znake: ._-', + 'original_not_found' => 'Originalne datoteke oziroma mape ni mogoče najti', + 'already_exists' => 'Datoteka oziroma mapa s tem imenom že obstaja', + 'error_renaming' => 'Napaka pri preimenovanju datoteke oziroma mape', + 'name_cant_be_empty' => 'Ime ne more biti prazno', + 'too_large' => 'Naložena datoteka je prevelika. Največja dovoljena velikost datoteke je :max_size', + 'type_not_allowed' => 'Dovoljeni so le formati datotek: :alowed_types', + 'file_not_valid' => 'Neveljavna datoteka', + 'error_uploading_file' => "Napaka pri nalaganju datoteke ':name': :error", + 'move_please_select' => 'izberite', + 'move_destination' => 'Ciljna mapa', + 'move_popup_title' => 'Premakni oblikovne datoteke', + 'move_button' => 'Premakni', + 'selected_files_not_found' => 'Izbranih datotek ni mogoče najti', + 'select_destination_dir' => 'Prosimo, izberite ciljno mapo', + 'destination_not_found' => 'Ciljne mape ni mogoče najti', + 'error_moving_file' => 'Napaka pri premikanju datoteke :file', + 'error_moving_directory' => 'Napaka pri premikanju mape :dir', + 'error_deleting_directory' => 'Napaka pri brisanju originalne mape :dir', + 'no_list_records' => 'Ni najdenih datotek.', + 'delete_confirm' => 'Želite izbrisati izbrane datoteke ali mape?', + 'path' => 'Lokacija', + ], + 'component' => [ + 'menu_label' => 'Komponente', + 'unnamed' => 'Neimenovano', + 'no_description' => 'Opis ni podan', + 'alias' => 'Vzdevek', + 'alias_description' => 'Unikatno ime komponente, ki se uporablja na strani ali v kodi postavitve.', + 'validation_message' => 'Vzdevki komponent so obvezni in lahko vsebujejo le latinične znake, številke in podčrtaje. Vzdevki naj se začnejo z latiničnim znakom.', + 'invalid_request' => 'Predloge ni bilo mogoče shraniti zaradi neveljavnih podatkov komponente.', + 'no_records' => 'Ni najdenih komponent.', + 'not_found' => "Komponente :name ni mogoče najti.", + 'method_not_found' => "Komponenta ':name' ne vsebuje metode ':method'.", + ], + 'template' => [ + 'invalid_type' => 'Neznan format predloge.', + 'not_found' => 'Predloge ni mogoče najti.', + 'saved' => 'Predloga je shranjena.', + 'no_list_records' => 'Ni najdenih zapisov.', + 'delete_confirm' => 'Želite izbrisati izbrane predloge?', + 'order_by' => 'Razvrsti po', + ], + 'permissions' => [ + 'name' => 'CMS', + 'manage_content' => 'Upravljanje datotek z vsebino spletne strani', + 'manage_assets' => 'Upravljanje z oblikovnimi datotekami - slike, JavaScript, CSS datoteke', + 'manage_pages' => 'Ustvarjanje, spremeninjanje ali brisanje strani', + 'manage_layouts' => 'Ustvarjanje, spremeninjanje ali brisanje CMS postavitev', + 'manage_partials' => 'Ustvarjanje, spremeninjanje ali brisanje CMS predlog', + 'manage_themes' => 'Aktiviranje, deaktiviranje ali konfiguriranje CMS tem', + 'manage_theme_options' => 'Konfiguriranje možnosti prilagajanja za aktivno temo', + ], + 'theme_log' => [ + 'hint' => 'V tem dnevniku so prikazane vse spremembe teme, ki so jih naredili administratorji v administraciji.', + 'menu_label' => 'Dnevnik sprememb teme', + 'menu_description' => 'Pokaži spremembe aktivne teme.', + 'empty_link' => 'Sprazni dnevnik sprememb teme', + 'empty_loading' => 'Praznjenje dnevnika sprememb...', + 'empty_success' => 'Dnevnik sprememb je izpraznjen', + 'return_link' => 'Vrni se na dnevnik sprememb teme', + 'id' => 'ID', + 'id_label' => 'ID dnevnika', + 'created_at' => 'Čas in datum', + 'user' => 'Uporabnik', + 'type' => 'Tip', + 'type_create' => 'Ustvari', + 'type_update' => 'Posodobi', + 'type_delete' => 'Izbriši', + 'theme_name' => 'Tema', + 'theme_code' => 'Koda teme', + 'old_template' => 'Predloga (stara)', + 'new_template' => 'Predloga (nova)', + 'template' => 'Predloga', + 'diff' => 'Spremembe', + 'old_value' => 'Stara vrednost', + 'new_value' => 'Nova vrednost', + 'preview_title' => 'Spremembe predloge', + 'template_updated' => 'Predloga je posodobljena', + 'template_created' => 'Predloga je ustvarjena', + 'template_deleted' => 'Predloga je izbrisana', + ], +]; diff --git a/modules/system/assets/js/lang/lang.sl.js b/modules/system/assets/js/lang/lang.sl.js new file mode 100644 index 0000000000..0caba5199d --- /dev/null +++ b/modules/system/assets/js/lang/lang.sl.js @@ -0,0 +1,299 @@ +/* + * This file has been compiled from: /modules/system/lang/sl/client.php + */ +if ($.oc === undefined) $.oc = {} +if ($.oc.langMessages === undefined) $.oc.langMessages = {} +$.oc.langMessages['sl'] = $.extend( + $.oc.langMessages['sl'] || {}, + {"markdowneditor":{"formatting":"Oblikovanje","quote":"Citat","code":"Koda","header1":"Naslov 1","header2":"Naslov 2","header3":"Naslov 3","header4":"Naslov 4","header5":"Naslov 5","header6":"Naslov 6","bold":"Krepko","italic":"Le\u017ee\u010de","unorderedlist":"Ne\u0161tevil\u010dni seznam","orderedlist":"\u0160tevil\u010dni seznam","video":"Video","image":"Slika","link":"Povezava","horizontalrule":"Vstavi vodoravno \u010drto","fullscreen":"Celozaslonski na\u010din","preview":"Predogled"},"mediamanager":{"insert_link":"Vstavi povezavo","insert_image":"Vstavi sliko","insert_video":"Vstavi video posnetek","insert_audio":"Vstavi zvo\u010dni posnetek","invalid_file_empty_insert":"Izberite datoteko, do katere \u017eelite vstaviti povezavo.","invalid_file_single_insert":"Izberite eno samo datoteko.","invalid_image_empty_insert":"Izberite slike za vstavljanje.","invalid_video_empty_insert":"Izberite video posnetek za vstavljanje.","invalid_audio_empty_insert":"Izberite zvo\u010dni posnetek za vstavljanje."},"alert":{"confirm_button_text":"V redu","cancel_button_text":"Prekli\u010di","widget_remove_confirm":"Odstrani ta vti\u010dnik?"},"datepicker":{"previousMonth":"Prej\u0161nji mesec","nextMonth":"Naslednji mesec","months":["Januar","Februar","Marec","April","Maj","Junij","Julij","Avgust","September","Oktober","November","December"],"weekdays":["Nedelja","Ponedeljek","Torek","Sreda","\u010cetrtek","Petek","Sobota"],"weekdaysShort":["Ned","Pon","Tor","Sre","\u010cet","Pet","Sob"]},"colorpicker":{"choose":"Ok"},"filter":{"group":{"all":"vsi"},"scopes":{"apply_button_text":"Uporabi","clear_button_text":"Po\u010disti"},"dates":{"all":"vsi","filter_button_text":"Filtriraj","reset_button_text":"Ponastavi","date_placeholder":"Datum","after_placeholder":"Po","before_placeholder":"Pred"},"numbers":{"all":"vsi","filter_button_text":"Filtriraj","reset_button_text":"Ponastavi","min_placeholder":"Min","max_placeholder":"Max"}},"eventlog":{"show_stacktrace":"Prika\u017ei sled dogodkov","hide_stacktrace":"Skrij sled dogodkov","tabs":{"formatted":"Oblikovano","raw":"Brez oblikovanja"},"editor":{"title":"Urejevalnik izvorne kode","description":"Va\u0161 operacijski sistem mora biti nastavljen tako, da upo\u0161teva eno od teh URL shem.","openWith":"Za odpiranje uporabi","remember_choice":"Zapomni si izbrane nastavitve za to sejo","open":"Odpri","cancel":"Prekli\u010di"}}} +); + +//! moment.js locale configuration v2.22.2 + +;(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' + && typeof require === 'function' ? factory(require('../moment')) : + typeof define === 'function' && define.amd ? define(['../moment'], factory) : + factory(global.moment) +}(this, (function (moment) { 'use strict'; + + function translate(number, withoutSuffix, key, isFuture) { + var result = number + ' '; + switch (key) { + case 's': // a few seconds / in a few seconds / a few seconds ago + return (withoutSuffix || isFuture) ? 'nekaj sekund' : 'nekaj sekundami'; + case 'ss': // 9 seconds / in 9 seconds / 9 seconds ago + if (withoutSuffix) { + if (number == 1) { + return result + 'sekunda'; + } else if (number == 2) { + return result + 'sekundi'; + } else if (number == 3 || number == 4) { + return result + 'sekunde'; + } else { + return result + 'sekund'; + } + } else if (isFuture) { + if (number == 1) { + return result + 'sekundo'; + } else if (number == 2) { + return result + 'sekundi'; + } else if (number == 3 || number == 4) { + return result + 'sekunde'; + } else { + return result + 'sekund'; + } + } else { + if (number == 1) { + return result + 'sekundo'; + } else if (number == 2) { + return result + 'sekundama'; + } else { + return result + 'sekundami'; + } + } + break; + case 'm': // a minute / in a minute / a minute ago + return withoutSuffix ? 'minuta' : 'minuto'; + case 'mm': // 9 minutes / in 9 minutes / 9 minutes ago + if (withoutSuffix) { + if (number == 1) { + return result + 'minuta'; + } else if (number == 2) { + return result + 'minuti'; + } else if (number == 3 || number == 4) { + return result + 'minute'; + } else { + return result + 'minut'; + } + } else if (isFuture) { + if (number == 1) { + return result + 'minuto'; + } else if (number == 2) { + return result + 'minuti'; + } else if (number == 3 || number == 4) { + return result + 'minute'; + } else { + return result + 'minut'; + } + } else { + if (number == 1) { + return result + 'minuto'; + } else if (number == 2) { + return result + 'minutama'; + } else { + return result + 'minutami'; + } + } + break; + case 'h': // an hour / in an hour / an hour ago + return withoutSuffix ? 'ura' : 'eno uro'; + case 'hh': // 9 hours / in 9 hours / 9 hours ago + if (withoutSuffix) { + if (number == 1) { + return result + 'ura'; + } else if (number == 2) { + return result + 'uri'; + } else if (number == 3 || number == 4) { + return result + 'ure'; + } else { + return result + 'ur'; + } + } else if (isFuture) { + if (number == 1) { + return result + 'uro'; + } else if (number == 2) { + return result + 'uri'; + } else if (number == 3 || number == 4) { + return result + 'ure'; + } else { + return result + 'ur'; + } + } else { + if (number == 1) { + return result + 'uro'; + } else if (number == 2) { + return result + 'urama'; + } else { + return result + 'urami'; + } + } + break; + case 'd': // a day / in a day / a day ago + return withoutSuffix ? 'dan' : (isFuture ? 'en dan' : 'enim dnem'); + case 'dd': // 9 days / in 9 days / 9 days ago + if (withoutSuffix) { + if (number == 1) { + return result + 'dan'; + } else if (number == 2) { + return result + 'dneva'; + } else if (number == 3 || number == 4) { + return result + 'dnevi'; + } else { + return result + 'dni'; + } + } else if (isFuture) { + if (number == 1) { + return result + 'dan'; + } else { + return result + 'dni'; + } + } else { + if (number == 1) { + return result + 'dnevom'; + } else if (number == 2) { + return result + 'dnevoma'; + } else { + return result + 'dnevi'; + } + } + break; + case 'M': // a month / in a month / a month ago + return withoutSuffix ? 'mesec' : (isFuture ? 'en mesec' : 'enim mesecem'); + case 'MM': // 9 months / in 9 months / 9 months ago + if (withoutSuffix) { + if (number == 1) { + return result + 'mesec'; + } else if (number == 2) { + return result + 'meseca'; + } else if (number == 3 || number == 4) { + return result + 'meseci'; + } else { + return result + 'mesecev'; + } + } else if (isFuture) { + if (number == 1) { + return result + 'mesec'; + } else if (number == 2) { + return result + 'meseca'; + } else if (number == 3 || number == 4) { + return result + 'mesece'; + } else { + return result + 'mesecev'; + } + } else { + if (number == 1) { + return result + 'mesecom'; + } else if (number == 2) { + return result + 'mesecema'; + } else { + return result + 'meseci'; + } + } + break; + case 'y': // a year / in a year / a year ago + return withoutSuffix ? 'leto' : (isFuture ? 'eno leto' : 'enim letom'); + case 'yy': // 9 years / in 9 years / 9 years ago + if (withoutSuffix) { + if (number == 1) { + return result + 'leto'; + } else if (number == 2) { + return result + 'leti'; + } else if (number == 3 || number == 4) { + return result + 'leta'; + } else { + return result + 'let'; + } + } else if (isFuture) { + if (number == 1) { + return result + 'leto'; + } else if (number == 2) { + return result + 'leti'; + } else if (number == 3 || number == 4) { + return result + 'leta'; + } else { + return result + 'let'; + } + } else { + if (number == 1) { + return result + 'letom'; + } else if (number == 2) { + return result + 'letoma'; + } else { + return result + 'leti'; + } + } + break; + } + } + + var sl = moment.defineLocale('sl', { + months : 'januar_februar_marec_april_maj_junij_julij_avgust_september_oktober_november_december'.split('_'), + monthsShort : 'jan_feb_mar_apr_maj_jun_jul_avg_sep_okt_nov_dec'.split('_'), + weekdays : 'nedelja_ponedeljek_torek_sreda_\u010detrtek_petek_sobota'.split('_'), + weekdaysShort : 'ned_pon_tor_sre_\u010det_pet_sob'.split('_'), + weekdaysMin : 'ne_po_to_sr_\u010de_pe_so'.split('_'), + longDateFormat : { + LT : 'H:mm', + LTS : 'H:mm:ss', + L : 'DD.MM.YYYY', + LL : 'D. MMMM YYYY', + LLL : 'D. MMMM YYYY H:mm', + LLLL : 'dddd, D. MMMM YYYY H:mm' + }, + calendar : { + sameDay : '[danes ob] LT', + nextDay : '[jutri ob] LT', + nextWeek: function () { + switch (this.day()) { + case 0: + return '[v nedeljo ob] LT'; + case 1: + case 2: + return '[v] dddd [ob] LT'; + case 3: + return '[v sredo ob] LT'; + case 4: + case 5: + return '[v] dddd [ob] LT'; + case 6: + return '[v soboto ob] LT'; + } + }, + lastDay : '[včeraj ob] LT', + lastWeek: function () { + switch (this.day()) { + case 0: + return '[prej\u0161njo nedeljo ob] LT'; + case 1: + case 2: + return '[prej\u0161nji] dddd [ob] LT'; + case 3: + return '[prej\u0161njo sredo ob] LT'; + case 4: + case 5: + return '[prej\u0161nji] dddd [ob] LT'; + case 6: + return '[prej\u0161njo soboto ob] LT'; + } + }, + sameElse : 'L' + }, + relativeTime : { + future : '\u010dez %s', + past : 'pred %s', + s : translate, + ss : translate, + m : translate, + mm : translate, + h : translate, + hh : translate, + d : translate, + dd : translate, + M : translate, + MM : translate, + y : translate, + yy : translate + }, + dayOfMonthOrdinalParse: /\d{1,2}\./, + ordinal : '%d.', + week : { + dow : 1, // Monday is the first day of the week. + doy : 4 // The week that contains Jan 4th is the first week of the year. + } + }); + + return sl; + +}))); + diff --git a/modules/system/lang/ar/lang.php b/modules/system/lang/ar/lang.php index 74814f6c75..91ca67bd62 100644 --- a/modules/system/lang/ar/lang.php +++ b/modules/system/lang/ar/lang.php @@ -40,6 +40,7 @@ 'fi' => 'Suomi', 'sv' => 'Svenska', 'sk' => 'Slovenský', + 'sl' => 'Slovenščina', 'tr' => 'Türkçe', 'uk' => 'Українська мова', 'zh-cn' => '简体中文', diff --git a/modules/system/lang/en/lang.php b/modules/system/lang/en/lang.php index 028f5feed5..4ff42f4d80 100644 --- a/modules/system/lang/en/lang.php +++ b/modules/system/lang/en/lang.php @@ -41,6 +41,7 @@ 'fi' => 'Suomi', 'sv' => 'Svenska', 'sk' => 'Slovenský', + 'sl' => 'Slovenščina', 'th' => 'ไทย', 'tr' => 'Türkçe', 'uk' => 'Українська мова', diff --git a/modules/system/lang/et/lang.php b/modules/system/lang/et/lang.php index 5ca2e05424..85ff201883 100644 --- a/modules/system/lang/et/lang.php +++ b/modules/system/lang/et/lang.php @@ -36,6 +36,7 @@ 'ru' => 'Русский', 'sv' => 'Svenska', 'sk' => 'Slovenský', + 'sl' => 'Slovenščina', 'tr' => 'Türkçe', 'zh-cn' => '简体中文', 'zh-tw' => '繁體中文', diff --git a/modules/system/lang/fa/lang.php b/modules/system/lang/fa/lang.php index ef6472bd6d..fc65f4d8a6 100644 --- a/modules/system/lang/fa/lang.php +++ b/modules/system/lang/fa/lang.php @@ -39,6 +39,7 @@ 'fi' => 'Suomi', 'sv' => 'Svenska', 'sk' => 'Slovenský', + 'sl' => 'Slovenščina', 'tr' => 'Türkçe', 'uk' => 'Українська мова', 'zh-cn' => '简体中文', diff --git a/modules/system/lang/fi/lang.php b/modules/system/lang/fi/lang.php index 2add07a9ff..0bb43eed5e 100644 --- a/modules/system/lang/fi/lang.php +++ b/modules/system/lang/fi/lang.php @@ -39,6 +39,7 @@ 'ru' => 'Русский', 'sv' => 'Svenska', 'sk' => 'Slovenský', + 'sl' => 'Slovenščina', 'tr' => 'Türkçe', 'uk' => 'Українська мова', 'zh-cn' => '简体中文', diff --git a/modules/system/lang/lt/lang.php b/modules/system/lang/lt/lang.php index 0e481812ee..45ad1bd02f 100644 --- a/modules/system/lang/lt/lang.php +++ b/modules/system/lang/lt/lang.php @@ -35,6 +35,7 @@ 'ru' => 'Русский', 'sv' => 'Svenska', 'sk' => 'Slovenský', + 'sl' => 'Slovenščina', 'tr' => 'Türk', 'zh-cn' => '简体中文', 'zh-tw' => '繁體中文', diff --git a/modules/system/lang/nl/lang.php b/modules/system/lang/nl/lang.php index 74cb99a479..de4064a6be 100644 --- a/modules/system/lang/nl/lang.php +++ b/modules/system/lang/nl/lang.php @@ -41,6 +41,7 @@ 'fi' => 'Suomi', 'sv' => 'Svenska', 'sk' => 'Slovenský', + 'sl' => 'Slovenščina', 'tr' => 'Türkçe', 'uk' => 'Українська мова', 'zh-cn' => '简体中文', diff --git a/modules/system/lang/pt-pt/lang.php b/modules/system/lang/pt-pt/lang.php index e534d21c1f..fe8836c120 100644 --- a/modules/system/lang/pt-pt/lang.php +++ b/modules/system/lang/pt-pt/lang.php @@ -35,6 +35,7 @@ 'ru' => 'Russo', 'sv' => 'Suéco', 'sk' => 'Esloveno', + 'sl' => 'Slovenščina', 'tr' => 'Turco', 'zh-cn' => 'Chinês', 'zh-tw' => 'Tailandês', diff --git a/modules/system/lang/sk/lang.php b/modules/system/lang/sk/lang.php index 18e32360e6..fd2209164c 100644 --- a/modules/system/lang/sk/lang.php +++ b/modules/system/lang/sk/lang.php @@ -39,6 +39,7 @@ 'fi' => 'Suomi', 'sv' => 'Svenska', 'sk' => 'Slovenský', + 'sl' => 'Slovenščina', 'tr' => 'Türkçe', 'uk' => 'Українська мова', 'zh-cn' => '简体中文', diff --git a/modules/system/lang/sl/client.php b/modules/system/lang/sl/client.php new file mode 100644 index 0000000000..84ffa7103d --- /dev/null +++ b/modules/system/lang/sl/client.php @@ -0,0 +1,115 @@ + [ + 'formatting' => 'Oblikovanje', + 'quote' => 'Citat', + 'code' => 'Koda', + 'header1' => 'Naslov 1', + 'header2' => 'Naslov 2', + 'header3' => 'Naslov 3', + 'header4' => 'Naslov 4', + 'header5' => 'Naslov 5', + 'header6' => 'Naslov 6', + 'bold' => 'Krepko', + 'italic' => 'Ležeče', + 'unorderedlist' => 'Neštevilčni seznam', + 'orderedlist' => 'Številčni seznam', + 'video' => 'Video', + 'image' => 'Slika', + 'link' => 'Povezava', + 'horizontalrule' => 'Vstavi vodoravno črto', + 'fullscreen' => 'Celozaslonski način', + 'preview' => 'Predogled', + ], + 'mediamanager' => [ + 'insert_link' => 'Vstavi povezavo', + 'insert_image' => 'Vstavi sliko', + 'insert_video' => 'Vstavi video posnetek', + 'insert_audio' => 'Vstavi zvočni posnetek', + 'invalid_file_empty_insert' => 'Izberite datoteko, do katere želite vstaviti povezavo.', + 'invalid_file_single_insert' => 'Izberite eno samo datoteko.', + 'invalid_image_empty_insert' => 'Izberite slike za vstavljanje.', + 'invalid_video_empty_insert' => 'Izberite video posnetek za vstavljanje.', + 'invalid_audio_empty_insert' => 'Izberite zvočni posnetek za vstavljanje.', + ], + 'alert' => [ + 'confirm_button_text' => 'V redu', + 'cancel_button_text' => 'Prekliči', + 'widget_remove_confirm' => 'Odstrani ta vtičnik?', + ], + 'datepicker' => [ + 'previousMonth' => 'Prejšnji mesec', + 'nextMonth' => 'Naslednji mesec', + 'months' => [ + 'Januar', + 'Februar', + 'Marec', + 'April', + 'Maj', + 'Junij', + 'Julij', + 'Avgust', + 'September', + 'Oktober', + 'November', + 'December' + ], + 'weekdays' => ['Nedelja', 'Ponedeljek', 'Torek', 'Sreda', 'Četrtek', 'Petek', 'Sobota'], + 'weekdaysShort' => ['Ned', 'Pon', 'Tor', 'Sre', 'Čet', 'Pet', 'Sob'], + ], + 'colorpicker' => [ + 'choose' => 'Ok', + ], + 'filter' => [ + 'group' => [ + 'all' => 'vsi', + ], + 'scopes' => [ + 'apply_button_text' => 'Uporabi', + 'clear_button_text' => 'Počisti', + ], + 'dates' => [ + 'all' => 'vsi', + 'filter_button_text' => 'Filtriraj', + 'reset_button_text' => 'Ponastavi', + 'date_placeholder' => 'Datum', + 'after_placeholder' => 'Po', + 'before_placeholder' => 'Pred', + ], + 'numbers' => [ + 'all' => 'vsi', + 'filter_button_text' => 'Filtriraj', + 'reset_button_text' => 'Ponastavi', + 'min_placeholder' => 'Min', + 'max_placeholder' => 'Max', + ] + ], + 'eventlog' => [ + 'show_stacktrace' => 'Prikaži sled dogodkov', + 'hide_stacktrace' => 'Skrij sled dogodkov', + 'tabs' => [ + 'formatted' => 'Oblikovano', + 'raw' => 'Brez oblikovanja', + ], + 'editor' => [ + 'title' => 'Urejevalnik izvorne kode', + 'description' => 'Vaš operacijski sistem mora biti nastavljen tako, da upošteva eno od teh URL shem.', + 'openWith' => 'Za odpiranje uporabi', + 'remember_choice' => 'Zapomni si izbrane nastavitve za to sejo', + 'open' => 'Odpri', + 'cancel' => 'Prekliči', + ], + ], +]; diff --git a/modules/system/lang/sl/lang.php b/modules/system/lang/sl/lang.php new file mode 100644 index 0000000000..7d3c7bba63 --- /dev/null +++ b/modules/system/lang/sl/lang.php @@ -0,0 +1,478 @@ + [ + 'name' => 'OctoberCMS', + 'tagline' => 'Nazaj k osnovam', + ], + 'locale' => [ + 'ar' => 'العربية', + 'be' => 'Беларуская', + 'bg' => 'Български', + 'ca' => 'Català', + 'cs' => 'Čeština', + 'da' => 'Dansk', + 'en' => 'English (United States)', + 'en-au' => 'English (Australia)', + 'en-ca' => 'English (Canada)', + 'en-gb' => 'English (United Kingdom)', + 'et' => 'Eesti', + 'de' => 'Deutsch', + 'el' => 'Ελληνικά', + 'es' => 'Español', + 'es-ar' => 'Español (Argentina)', + 'fa' => 'فارسی', + 'fr' => 'Français', + 'fr-ca' => 'Français (Canada)', + 'hu' => 'Magyar', + 'id' => 'Bahasa Indonesia', + 'it' => 'Italiano', + 'ja' => '日本語', + 'kr' => '한국어', + 'lt' => 'Lietuvių', + 'lv' => 'Latviešu', + 'nb-no' => 'Norsk (Bokmål)', + 'nl' => 'Nederlands', + 'pl' => 'Polski', + 'pt-br' => 'Português (Brasil)', + 'pt-pt' => 'Português (Portugal)', + 'ro' => 'Română', + 'ru' => 'Русский', + 'fi' => 'Suomi', + 'sv' => 'Svenska', + 'sk' => 'Slovenský', + 'sl' => 'Slovenščina', + 'th' => 'ไทย', + 'tr' => 'Türkçe', + 'uk' => 'Українська мова', + 'zh-cn' => '简体中文', + 'zh-tw' => '繁體中文', + 'vn' => 'Tiếng việt', + ], + 'directory' => [ + 'create_fail' => 'Mape :name ni mogoče ustvariti', + ], + 'file' => [ + 'create_fail' => 'Datoteke :name ni mogoče ustvariti', + ], + 'combiner' => [ + 'not_found' => "Datoteke za kombiniranje ':name' ni mogoče najti.", + ], + 'system' => [ + 'name' => 'Sistem', + 'menu_label' => 'Sistem', + 'categories' => [ + 'misc' => 'Razno', + 'logs' => 'Dnevniki', + 'mail' => 'E-pošta', + 'shop' => 'Trgovina', + 'team' => 'Ekipa', + 'users' => 'Uporabniki', + 'system' => 'Sistem', + 'social' => 'Družbeno', + 'backend' => 'Administracija', + 'events' => 'Dogodki', + 'customers' => 'Stranke', + 'my_settings' => 'Moje nastavitve', + 'notifications' => 'Obvestila', + ], + ], + 'theme' => [ + 'label' => 'Tema', + 'unnamed' => 'Neimenovana tema', + 'name' => [ + 'label' => 'Ime teme', + 'help' => 'Poimenujte temo po njeni unikatni kodi, npr. RainLab.Vanilla', + ], + ], + 'themes' => [ + 'install' => 'Namesti teme', + 'search' => 'išči teme za namestitev...', + 'installed' => 'Nameščene teme', + 'no_themes' => 'Ni nameščenih tem iz trga.', + 'recommended' => 'Priporočeno', + 'remove_confirm' => 'Ali ste prepričani, da želite odstraniti to temo?', + ], + 'plugin' => [ + 'label' => 'Vtičnik', + 'unnamed' => 'Neimenovan vtičnik', + 'name' => [ + 'label' => 'Ime vtičnika', + 'help' => 'Poimenujte vtičnik po njegovi unikatni kodi, npr. RainLab.Blog', + ], + 'by_author' => 'Od :name', + ], + 'plugins' => [ + 'manage' => 'Upravljanje vtičnikov', + 'install' => 'Namesti vtičnike in teme', + 'install_products' => 'Namesti produkte', + 'search' => 'išči vtičnike za namestitev...', + 'installed' => 'Nameščeni vtičniki', + 'no_plugins' => 'Ni nameščenih vtičnikov iz trga.', + 'recommended' => 'Priporočeno', + 'plugin_label' => 'Vtičnik', + 'unknown_plugin' => 'Vtičnik je bil odstranjen iz datotečnega sistema.', + 'select_label' => 'Izberite dejanje...', + 'bulk_actions_label' => 'Skupna dejanja', + 'check_yes' => 'Da', + 'check_no' => 'Ne', + 'unfrozen' => 'Posodobitve so omogočene', + 'enabled' => 'Vtičnik je omogočen', + 'freeze' => 'onemogoči posodobitve za', + 'unfreeze' => 'omogoči posodobitve za', + 'enable' => 'omogoči', + 'disable' => 'onemogoči', + 'refresh' => 'ponastavi', + 'remove' => 'Odstrani', + 'freeze_label' => 'Onemogoči posodobitve', + 'unfreeze_label' => 'Omogoči posodobitve', + 'enable_label' => 'Omogoči vtičnike', + 'disable_label' => 'Onemogoči vtičnike', + 'refresh_label' => 'Ponastavi podatke vtičnikov', + 'action_confirm' => 'Ali ste prepričani, da želite :action-ti te vtičnike?', + 'freeze_success' => 'Posodobitve za izbrane vtičnike so onemogočene.', + 'unfreeze_success' => 'Posodobitve za izbrane vtičnike so omogočene.', + 'enable_success' => 'Izbrani vtičniki so omogočeni.', + 'disable_success' => 'Izbrani vtičniki so onemogočeni.', + 'refresh_confirm' => 'Ali ste prepričani, da želite ponastaviti izbrane vtičnike? S tem boste ponastavili podatke vsakega posameznega vtičnika in ga obnovili v začetno stanje namestitve.', + 'refresh_success' => 'Izbrani vtičniki so bili ponastavljeni.', + 'remove_confirm' => 'Ali ste prepričani, da želite odstraniti izbrane vtičnike? S tem boste odstranili tudi vse povezane podatke.', + 'remove_success' => 'Izbrani vtičniki so bili odstranjeni.', + ], + 'project' => [ + 'name' => 'Projekt', + 'owner_label' => 'Lastnik', + 'attach' => 'Pripni projekt', + 'detach' => 'Odpni projekt', + 'none' => 'Nobeden', + 'id' => [ + 'label' => 'ID projekta', + 'help' => 'Kako poiskati ID vašega projekta', + 'missing' => 'Določite ID projekta za uporabo.', + ], + 'detach_confirm' => 'Ali ste prepričani, da želite odpeti ta projekt?', + 'unbind_success' => 'Projekt je bil odpet.', + ], + 'settings' => [ + 'menu_label' => 'Nastavitve', + 'not_found' => 'Navedenih nastavitev ni mogoče najti.', + 'missing_model' => 'Na strani z nastavitvami manjka definicija Modela.', + 'update_success' => 'Nastavitve za ":name" so shranjene.', + 'return' => 'Vrni se na sistemske nastavitve', + 'search' => 'Iskanje', + ], + 'mail' => [ + 'log_file' => 'Dnevniška datoteka', + 'menu_label' => 'Nastavitve e-pošte', + 'menu_description' => 'Upravljanje z nastavitvami za pošiljanje e-pošte.', + 'general' => 'Splošno', + 'method' => 'Način za e-pošto', + 'sender_name' => 'Ime pošiljatelja', + 'sender_email' => 'E-pošta pošiljatelja', + 'php_mail' => 'PHP mail', + 'smtp' => 'SMTP', + 'smtp_address' => 'SMTP naslov', + 'smtp_authorization' => 'Obvezna SMTP avtorizacija', + 'smtp_authorization_comment' => 'Označite, če vaš SMTP strežnik zahteva avtorizacijo.', + 'smtp_username' => 'Uporabniško ime', + 'smtp_password' => 'Geslo', + 'smtp_port' => 'SMTP vrata (port)', + 'smtp_ssl' => 'Obvezna SSL povezava', + 'smtp_encryption' => 'Enkripcijski protokol za SMTP', + 'smtp_encryption_none' => 'Brez enkripcije', + 'smtp_encryption_tls' => 'TLS', + 'smtp_encryption_ssl' => 'SSL', + 'sendmail' => 'Sendmail', + 'sendmail_path' => 'Sendmail lokacija', + 'sendmail_path_comment' => 'Določite lokacijo Sendmail programa.', + 'mailgun' => 'Mailgun', + 'mailgun_domain' => 'Mailgun domena', + 'mailgun_domain_comment' => 'Določite domensko ime za Mailgun (Mailgun domain name).', + 'mailgun_secret' => 'Mailgun geslo', + 'mailgun_secret_comment' => 'Vnesite API ključ za Mailgun (Mailgun API key).', + 'mandrill' => 'Mandrill', + 'mandrill_secret' => 'Mandrill geslo', + 'mandrill_secret_comment' => 'Vnesite API ključ za Mandrill (Mandrill API key).', + 'ses' => 'SES', + 'ses_key' => 'SES ključ', + 'ses_key_comment' => 'Vnesite API ključ za SES.', + 'ses_secret' => 'SES geslo', + 'ses_secret_comment' => 'Vnesite API ključ za SES (SES API secret key).', + 'sparkpost' => 'SparkPost', + 'sparkpost_secret' => 'SparkPost geslo', + 'sparkpost_secret_comment' => 'Vnesite skrivni API ključ za SparkPost (SparkPost API secret key).', + 'ses_region' => 'SES regija', + 'ses_region_comment' => 'Vnesite SES regijo (SES region, npr. us-east-1).', + 'drivers_hint_header' => 'Gonilniki niso nameščeni', + 'drivers_hint_content' => 'Ta način pošiljanja potrebuje namestitev vtičnika ":plugin".', + ], + 'mail_templates' => [ + 'menu_label' => 'E-poštne predloge', + 'menu_description' => 'Urejanje predlog in vsebin, ki se pošiljajo uporabnikom.', + 'new_template' => 'Nova predloga', + 'new_layout' => 'Nova postavitev', + 'new_partial' => 'Nova podpredloga', + 'template' => 'Predloga', + 'templates' => 'Predloge', + 'partial' => 'Podpredloga', + 'partials' => 'Podpredloge', + 'menu_layouts_label' => 'E-poštne postavitve', + 'menu_partials_label' => 'E-poštne predloge', + 'layout' => 'Postavitev', + 'layouts' => 'Postavitve', + 'no_layout' => '-- brez postavitve --', + 'name' => 'Ime', + 'name_comment' => 'Unikatno ime, ki se nanaša na to predlogo.', + 'code' => 'Koda', + 'code_comment' => 'Unikatna koda, ki se nanaša na to predlogo.', + 'subject' => 'Zadeva', + 'subject_comment' => 'Zadeva e-poštnega sporočila.', + 'description' => 'Opis', + 'content_html' => 'HTML', + 'content_css' => 'CSS', + 'content_text' => 'Neformatirano', + 'test_send' => 'Pošlji testno sporočilo', + 'test_success' => 'Testno sporočilo poslano.', + 'test_confirm' => 'Testno sporočilo bo poslano na :email. Nadaljujem?', + 'creating' => 'Ustvarjanje predloge...', + 'creating_layout' => 'Ustvarjanje postavitve...', + 'saving' => 'Shranjevanje predloge...', + 'saving_layout' => 'Shranjevane postavitve...', + 'delete_confirm' => 'Želite izbristi to predlogo?', + 'delete_layout_confirm' => 'Želite izbrisati to postavitev?', + 'deleting' => 'Brisanje predloge...', + 'deleting_layout' => 'Brisanje postavitve...', + 'sending' => 'Pošiljanje testnega sporočila...', + 'return' => 'Vrni se na seznam predlog', + 'options' => 'Možnosti', + 'disable_auto_inline_css' => 'Onemogoči vgrajeni CSS (inline)', + ], + 'mail_brand' => [ + 'menu_label' => 'Oblikovanje e-pošte', + 'menu_description' => 'Spremeninjanje barvne sheme in izgleda e-poštnih predlog.', + 'page_title' => 'Prilagoditev videza e-pošte', + 'sample_template' => [ + 'heading' => 'Naslov', + 'paragraph' => 'To je odstavek, ki vsebuje Lorem Ipsum tekst in povezavo. Cumque dicta
    doloremque eaque, enim error laboriosam pariatur possimus tenetur veritatis voluptas.', + 'table' => [ + 'item' => 'Element', + 'description' => 'Opis', + 'price' => 'Cena', + 'centered' => 'Centrirano', + 'right_aligned' => 'Desno-ravnano', + ], + 'buttons' => [ + 'primary' => 'Primarni gumb', + 'positive' => 'Pozitivni gumb', + 'negative' => 'Negativni gumb', + ], + 'panel' => 'Kako dobro izgleda ta barvni okvir?', + 'more' => 'Še nekaj besedila za konec.', + 'promotion' => 'Koda kupona: OCTOBER', + 'subcopy' => 'Noga sporočila na koncu e-poštne predloge.', + 'thanks' => 'Hvala', + ], + 'fields' => [ + '_section_background' => 'Ozadje', + 'body_bg' => 'Ozadje strani', + 'content_bg' => 'Ozadje vsebine', + 'content_inner_bg' => 'Ozadje notranje vsebine', + '_section_buttons' => 'Gumbi', + 'button_text_color' => 'Barva pisave gumba', + 'button_primary_bg' => 'Ozadje primarnega gumba', + 'button_positive_bg' => 'Ozadje pozitivnega gumba', + 'button_negative_bg' => 'Ozadje negativnega gumba', + '_section_type' => 'Tipografija', + 'header_color' => 'Barva glave', + 'heading_color' => 'Barva naslovov', + 'text_color' => 'Barva besedila', + 'link_color' => 'Barva povezav', + 'footer_color' => 'Barva noge', + '_section_borders' => 'Robovi', + 'body_border_color' => 'Barva roba strani', + 'subcopy_border_color' => 'Barva roba noge sporočila', + 'table_border_color' => 'Barva robov tabel', + '_section_components' => 'Komponente', + 'panel_bg' => 'Ozadje barvnega okvira', + 'promotion_bg' => 'Ozadje promocije', + 'promotion_border_color' => 'Barva robov promocije', + ], + ], + 'install' => [ + 'project_label' => 'Pripni na projekt', + 'plugin_label' => 'Namesti vtičnik', + 'theme_label' => 'Namesti temo', + 'missing_plugin_name' => 'Podajte ime vtičnika, ki ga želite namestiti.', + 'missing_theme_name' => 'Podajte ime teme, ki jo želite namestiti.', + 'install_completing' => 'Zaključevanje namestitvenega postopka', + 'install_success' => 'Produkt je bil uspešno nameščen', + ], + 'updates' => [ + 'title' => 'Upravljanje posodobitev', + 'name' => 'Posodobitev programske opreme', + 'menu_label' => 'Posodobitve in vtičniki', + 'menu_description' => 'Posodobitev sistema, upravljanje in nameščanje vtičnikov in tem.', + 'return_link' => 'Vrni se na sistemske posodobitve', + 'check_label' => 'Preveri za nove posodobitve', + 'retry_label' => 'Poskusi ponovno', + 'plugin_name' => 'Ime', + 'plugin_code' => 'Koda', + 'plugin_description' => 'Opis', + 'plugin_version' => 'Različica', + 'plugin_author' => 'Avtor', + 'plugin_not_found' => 'Vtičnika ni mogoče najti', + 'core_current_build' => 'Trenutna različica', + 'core_view_changelog' => 'Pokaži dnevnik sprememb', + 'core_build' => 'Različica :build', + 'core_build_help' => 'Na voljo je najnovejša različica.', + 'core_downloading' => 'Prenašanje datotek aplikacije', + 'core_extracting' => 'Ekstrahiranje datotek aplikacije', + 'core_set_build' => 'Nastavljanje številke različice', + 'changelog' => 'Dnevnik sprememb', + 'changelog_view_details' => 'Pokaži podrobnosti', + 'plugins' => 'Vtičniki', + 'themes' => 'Teme', + 'disabled' => 'Onemogočenih', + 'plugin_downloading' => 'Prenašanje vtičnika :name', + 'plugin_extracting' => 'Ekstrahiranje vtičnika :name', + 'plugin_version_none' => 'Nov vtičnik', + 'plugin_current_version' => 'Trenutna verzija', + 'theme_new_install' => 'Namestitev nove teme.', + 'theme_downloading' => 'Prenašanje teme :name', + 'theme_extracting' => 'Ekstrahiranje teme :name', + 'update_label' => 'Posodobitev programske opreme', + 'update_completing' => 'Zaključevanje posodabljanja', + 'update_loading' => 'Nalaganje razpoložljivih posodobitev...', + 'update_success' => 'Posodabljanje končano', + 'update_failed_label' => 'Posodabljanje ni bilo uspešno', + 'force_label' => 'Vsili posodobitev', + 'found' => [ + 'label' => 'Nove posodobitve so na voljo!', + 'help' => "Kliknite 'Posodobitev programske opreme' za začetek posodabljanja.", + ], + 'none' => [ + 'label' => 'Ni posodobitev', + 'help' => 'Nove posodobitve niso na voljo.', + ], + 'important_action' => [ + 'empty' => 'Izberite dejanje', + 'confirm' => 'Potrdi posodobitev', + 'skip' => 'Preskoči to posodobitev (le tokrat)', + 'ignore' => 'Preskoči to posodobitev (vedno)', + ], + 'important_action_required' => 'Potrebno je ukrepanje', + 'important_view_guide' => 'Oglejte si navodila za nadgradnjo', + 'important_view_release_notes' => 'Oglejte si opombe ob izdaji', + 'important_alert_text' => 'Nekatere posodobitve potrebujejo vašo pozornost.', + 'details_title' => 'Podrobnosti vtičnika', + 'details_view_homepage' => 'Odpri spletno stran', + 'details_readme' => 'Dokumentacija', + 'details_readme_missing' => 'Dokumentacija ni na voljo.', + 'details_changelog' => 'Dnevnik sprememb', + 'details_changelog_missing' => 'Dnevnik sprememb ni na voljo.', + 'details_upgrades' => 'Navodila za nadgradnjo', + 'details_upgrades_missing' => 'Navodila za nadgradnjo niso na voljo.', + 'details_licence' => 'Licenca', + 'details_licence_missing' => 'Licenca ni na voljo.', + 'details_current_version' => 'Trenutna različica', + 'details_author' => 'Avtor', + ], + 'server' => [ + 'connect_error' => 'Napaka pri povezavi s strežnikom.', + 'response_not_found' => 'Strežnika za posodobitve ni bilo mogoče najti.', + 'response_invalid' => 'Neveljaven odgovor s strani strežnika.', + 'response_empty' => 'Prazen odgovor s strani strežnika.', + 'file_error' => 'Strežniku ni uspelo dostaviti paketa.', + 'file_corrupt' => 'Datoteka s strežnika je poškodovana.', + ], + 'behavior' => [ + 'missing_property' => 'Objekt :class mora imeti definirano lastnost $:property, ki jo uporablja :behavior.', + ], + 'config' => [ + 'not_found' => 'Datoteke z nastavitvami :file, definirane za :location ni mogoče najti.', + 'required' => "Nastavitve uporabljene v :location morajo vsebovati vrednost ':property'.", + ], + 'zip' => [ + 'extract_failed' => "Datoteke ':file' ni mogoče ekstrahirati.", + ], + 'event_log' => [ + 'hint' => 'Ta dnevnik prikaže napake, ki se lahko pojavijo v aplikaciji in informacije za odpravljanje napak.', + 'menu_label' => 'Dnevnik dogodkov', + 'menu_description' => 'Prikaz dnevnika sistemskih sporočil z zabeležinimi časi in podrobnostmi.', + 'empty_link' => 'Počisti dnevnik dogodkov', + 'empty_loading' => 'Čiščenje dnevnika dogodkov...', + 'empty_success' => 'Dnevnik dogodkov je izpraznjen', + 'return_link' => 'Vrni se na dnevnik dogokov', + 'id' => 'ID', + 'id_label' => 'ID dogodka', + 'created_at' => 'Datum in čas', + 'message' => 'Sporočilo', + 'level' => 'Tip dogodka', + 'preview_title' => 'Dogodek', + ], + 'request_log' => [ + 'hint' => 'Ta dnevnik prikaže zahteve brskalnika, ki lahko potrebujejo pozornost. Če npr. obiskovalec odpre stran v CMS, ki je ni mogoče najti, se ustvari zapis s statusno kodo 404.', + 'menu_label' => 'Dnevnik zahtev', + 'menu_description' => 'Ogled slabih ali preusmerjenih zahtev, kot npr. Strani ni bilo mogoče najti (404).', + 'empty_link' => 'Počisti dnevnik zahtev', + 'empty_loading' => 'Čiščenje dnevnika zahtev...', + 'empty_success' => 'Dnevnik zahtev je izpraznjen', + 'return_link' => 'Vrni se na seznam zahtev', + 'id' => 'ID', + 'id_label' => 'ID dnevnika', + 'count' => 'Števec', + 'referer' => 'Reference', + 'url' => 'URL', + 'status_code' => 'Status', + 'preview_title' => 'Zahteva', + ], + 'permissions' => [ + 'name' => 'Sistem', + 'manage_system_settings' => 'Upravljanje sistemskih nastavitev', + 'manage_software_updates' => 'Upravljanje posodobitev programske opreme', + 'access_logs' => 'Prikaz sistemskih dnevnikov', + 'manage_mail_templates' => 'Upravljanje e-poštnih predlog', + 'manage_mail_settings' => 'Upravljanje e-poštnih nastavitev', + 'manage_other_administrators' => 'Upravljanje ostalih administratorjev', + 'impersonate_users' => 'Oponašanje uporabnikov', + 'manage_preferences' => 'Upravljanje z nastavitvami administracije', + 'manage_editor' => 'Upravljanje z nastavitvami urejevalnika kode', + 'view_the_dashboard' => 'Prikaz nadzorne plošče', + 'manage_default_dashboard' => 'Upravljanje s privzeto nadzorno ploščo', + 'manage_branding' => 'Prilaganje administracije', + ], + 'log' => [ + 'menu_label' => 'Nastavitve dnevnikov', + 'menu_description' => 'Določanje področji, ki naj uporabljajo dnevnike.', + 'default_tab' => 'Dnevniki', + 'log_events' => 'Dnevnik sistemskih dogodkov', + 'log_events_comment' => 'Shrani sistemske dogodke tudi v podatkovno bazo in ne samo v dnevniško datoteko.', + 'log_requests' => 'Beleži neuspešne zahteve', + 'log_requests_comment' => 'Zahteve brskalnika, ki lahko potrebujejo pozornost, kot na primer napake 404.', + 'log_theme' => 'Beleži spremembe tem', + 'log_theme_comment' => 'Kadar je sprememba teme narejena v administraciji.', + ], + 'media' => [ + 'invalid_path' => "Podana je nepravilna lokacija datoteke: ':path'.", + 'folder_size_items' => 'element(i)', + ], + 'page' => [ + 'custom_error' => [ + 'label' => 'Napaka strani', + 'help' => "Žal je prišlo do napake in strani ni mogoče prikazati.", + ], + 'invalid_token' => [ + 'label' => 'Neveljaven varnostni ključ', + ], + 'maintenance' => [ + 'label' => "Takoj bomo nazaj!", + 'help' => "Trenutno potekajo vzdrževalna dela, kmalu se vrnemo!", + 'message' => "Sporočilo:", + 'available_at' => "Poskusite znova po:", + ], + ], + 'pagination' => [ + 'previous' => 'Prejšnja', + 'next' => 'Naslednja', + ], +]; diff --git a/modules/system/lang/sl/validation.php b/modules/system/lang/sl/validation.php new file mode 100644 index 0000000000..0a934db296 --- /dev/null +++ b/modules/system/lang/sl/validation.php @@ -0,0 +1,121 @@ + '":attribute" mora biti sprejet.', + 'active_url' => '":attribute" ni veljaven URL naslov.', + 'after' => '":attribute" mora biti datum po :date.', + 'after_or_equal' => '":attribute" mora biti datum, enak ali kasnejši kot :date.', + 'alpha' => '":attribute" lahko vsebuje le črke.', + 'alpha_dash' => '":attribute" lahko vsebuje le črke, številke in pomišljaje.', + 'alpha_num' => '":attribute" lahko vsebuje le črke in številke.', + 'array' => '":attribute" mora biti niz elementov.', + 'before' => '":attribute" mora biti datum pred :date.', + 'before_or_equal' => '":attribute" mora biti datum pred ali enak datumu :date.', + 'between' => [ + 'numeric' => '":attribute" mora biti med :min in :max.', + 'file' => '":attribute" mora biti med :min in max: kB.', + 'string' => '":attribute" mora vsebovati med :min in :max znakov.', + 'array' => '":attribute" mora vsebovati med :min in :max elementov.', + ], + 'boolean' => '":attribute" mora biti Da (true) ali Ne (false).', + 'confirmed' => 'Potrditev polja ":attribute" se ne ujema.', + 'date' => '":attribute" ni veljaven datum.', + 'date_format' => '":attribute" se ne ujema s formatom :format.', + 'different' => '":attribute" in :other morata biti različna.', + 'digits' => '":attribute" mora vsebovati :digits številk.', + 'digits_between' => '":attribute" mora vsebovati med :min in :max številk.', + 'dimensions' => '":attribute" vsebuje neveljavne dimenzije slike.', + 'distinct' => '":attribute" polje ima podvojeno vrednost.', + 'email' => '":attribute" mora biti veljaven e-poštni naslov.', + 'exists' => 'Izbran element ":attribute" je neveljaven.', + 'file' => '":attribute" mora biti datoteka.', + 'filled' => '":attribute" polje mora vsebovati vrednost.', + 'image' => '":attribute" mora biti slika.', + 'in' => 'Izbran element ":attribute" je neveljaven.', + 'in_array' => 'Element ":attribute" ne obstaja v ":other".', + 'integer' => '":attribute" mora biti celo število.', + 'ip' => '":attribute" mora biti veljaven IP naslov.', + 'ipv4' => '":attribute" mora biti veljaven IPv4 naslov.', + 'ipv6' => '":attribute" mora biti veljaven IPv6 naslov.', + 'json' => '":attribute" mora biti veljaven JSON format.', + 'max' => [ + 'numeric' => ':attribute ne sme biti večji od :max.', + 'file' => ':attribute ne sme biti večji od :max kB.', + 'string' => ':attribute ne sme biti večji od :max znakov.', + 'array' => ':attribute ne sme vsebovati več kot :max elementov.', + ], + 'mimes' => ':attribute mora biti datoteka tipa :values.', + 'mimetypes' => ':attribute mora biti datoteka tipa :values.', + 'min' => [ + 'numeric' => ':attribute mora biti vsaj :min.', + 'file' => ':attribute mora imeti vsaj :min kB.', + 'string' => ':attribute mora imeti vsaj :min znakov.', + 'array' => ':attribute mora vsebovati vsaj :min elementov.', + ], + 'not_in' => 'Izbrani element ":attribute" je neveljaven.', + 'numeric' => '":attribute" mora biti število.', + 'present' => 'Polje za ":attribute" mora obstajati.', + 'regex' => 'Format za ":attribute" je neveljaven.', + 'required' => 'Polje za ":attribute" je obvezno.', + 'required_if' => 'Polje za ":attribute" je obvezno, kadar ima :other vrednost :value.', + 'required_unless' => 'Polje za ":attribute" je obvezno, razen kadar ima :other vrednosti :values.', + 'required_with' => 'Polje za ":attribute" je obvezno, kadar :values obstaja.', + 'required_with_all' => 'Polje za ":attribute" je obvezno, kadar :values obstaja.', + 'required_without' => 'Polje za ":attribute" je obvezno, kadar :values ne obstaja.', + 'required_without_all' => 'Polje za ":attribute" je obvezno, kadar :values ne obstaja.', + 'same' => '":attribute" in ":other" se morata ujemati.', + 'size' => [ + 'numeric' => ':attribute mora biti :size.', + 'file' => ':attribute mora imeti :size kB.', + 'string' => ':attribute mora vsebovati :size znakov.', + 'array' => ':attribute mora vsebovati :size elementov.', + ], + 'string' => ':attribute mora biti veljaven znakovni niz.', + 'timezone' => ':attribute mora biti veljavno območje.', + 'unique' => 'Element :attribute je že uporabljen.', + 'uploaded' => 'Elementa :attribute ni bilo mogoče naložiti.', + 'url' => 'Format elementa :attribute je neveljaven.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/modules/system/lang/tr/lang.php b/modules/system/lang/tr/lang.php index 38521a03a1..b057f50a09 100644 --- a/modules/system/lang/tr/lang.php +++ b/modules/system/lang/tr/lang.php @@ -41,6 +41,7 @@ 'fi' => 'Suomi', 'sv' => 'Svenska', 'sk' => 'Slovenský', + 'sl' => 'Slovenščina', 'tr' => 'Türkçe', 'uk' => 'Українська мова', 'zh-cn' => '简体中文', diff --git a/modules/system/lang/vn/lang.php b/modules/system/lang/vn/lang.php index c828f908e6..83a83c4bda 100644 --- a/modules/system/lang/vn/lang.php +++ b/modules/system/lang/vn/lang.php @@ -39,6 +39,7 @@ 'fi' => 'Suomi', 'sv' => 'Svenska', 'sk' => 'Slovenský', + 'sl' => 'Slovenščina', 'tr' => 'Türkçe', 'uk' => 'Українська мова', 'zh-cn' => '简体中文', From 8a8011bcc996ba1efc3edebbae85187b7131c72d Mon Sep 17 00:00:00 2001 From: Philipp Lang Date: Tue, 10 Dec 2019 10:21:56 +0100 Subject: [PATCH 148/157] Allow setting customview path for relation list (#4680) --- modules/backend/behaviors/RelationController.php | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/backend/behaviors/RelationController.php b/modules/backend/behaviors/RelationController.php index 2306b5ffbc..deb84260f9 100644 --- a/modules/backend/behaviors/RelationController.php +++ b/modules/backend/behaviors/RelationController.php @@ -666,6 +666,7 @@ protected function makeViewWidget() $config->recordsPerPage = $this->getConfig('view[recordsPerPage]'); $config->showCheckboxes = $this->getConfig('view[showCheckboxes]', !$this->readOnly); $config->recordUrl = $this->getConfig('view[recordUrl]', null); + $config->customViewPath = $this->getConfig('view[customViewPath]', null); $defaultOnClick = sprintf( "$.oc.relationBehavior.clickViewListRecord(':%s', '%s', '%s')", From 47b873aa9f63637ee31fd721d9c6477f5f16febb Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Tue, 10 Dec 2019 20:41:19 +1100 Subject: [PATCH 149/157] Recompile assets --- modules/system/assets/js/lang/lang.cs.js | 2 +- modules/system/assets/js/lang/lang.fr.js | 95 ++++--- modules/system/assets/js/lang/lang.sl.js | 332 ++++++++--------------- 3 files changed, 156 insertions(+), 273 deletions(-) diff --git a/modules/system/assets/js/lang/lang.cs.js b/modules/system/assets/js/lang/lang.cs.js index 4c573e9a65..adb7006284 100644 --- a/modules/system/assets/js/lang/lang.cs.js +++ b/modules/system/assets/js/lang/lang.cs.js @@ -5,7 +5,7 @@ if ($.oc === undefined) $.oc = {} if ($.oc.langMessages === undefined) $.oc.langMessages = {} $.oc.langMessages['cs'] = $.extend( $.oc.langMessages['cs'] || {}, - {"markdowneditor":{"formatting":"Form\u00e1tov\u00e1n\u00ed","quote":"Citace","code":"K\u00f3d","header1":"Nadpis 1","header2":"Nadpis 2","header3":"Nadpis 3","header4":"Nadpis 4","header5":"Nadpis 5","header6":"Nadpis 6","bold":"Tu\u010dn\u011b","italic":"Kurz\u00edvou","unorderedlist":"Ne\u010d\u00edslovan\u00fd seznam","orderedlist":"\u010c\u00edslovan\u00fd seznam","video":"Video","image":"Obr\u00e1zek","link":"Odkaz","horizontalrule":"Vlo\u017eit horizont\u00e1ln\u00ed linku","fullscreen":"Cel\u00e1 obrazovka","preview":"N\u00e1hled"},"mediamanager":{"insert_link":"Vlo\u017eit odkaz","insert_image":"Vlo\u017eit obr\u00e1zek","insert_video":"Vlo\u017eit video","insert_audio":"Vlo\u017eit zvuk","invalid_file_empty_insert":"Pros\u00edm vyberte soubor, na kter\u00fd se vlo\u017e\u00ed odkaz.","invalid_file_single_insert":"Vyberte jeden soubor.","invalid_image_empty_insert":"Vyberte soubor(y) pro vlo\u017een\u00ed.","invalid_video_empty_insert":"Vyberte video soubor pro vlo\u017een\u00ed.","invalid_audio_empty_insert":"Vyberte audio soubor pro vlo\u017een\u00ed."},"alert":{"confirm_button_text":"OK","cancel_button_text":"Zru\u0161it","widget_remove_confirm":"Odstranit widget?"},"datepicker":{"previousMonth":"P\u0159edchoz\u00ed m\u011bs\u00edc","nextMonth":"N\u00e1sleduj\u00edc\u00ed m\u011bs\u00edc","months":["Leden","\u00danor","B\u0159ezen","Duben","Kv\u011bten","\u010cerven","\u010cervenec","Srpen","Z\u00e1\u0159\u00ed","\u0158\u00edjen","Listopad","Prosinec"],"weekdays":["Ned\u011ble","Pond\u011bl\u00ed","\u00dater\u00fd","St\u0159eda","\u010ctvrtek","P\u00e1tek","Sobota"],"weekdaysShort":["Ne","Po","\u00dat","St","\u010ct","P\u00e1","So"]},"colorpicker":{"choose":"Ok"},"filter":{"group":{"all":"V\u0161e"},"scopes":{"apply_button_text":"Apply","clear_button_text":"Clear"},"dates":{"all":"V\u0161e","filter_button_text":"Filtrovat","reset_button_text":"Zru\u0161it","date_placeholder":"Datum","after_placeholder":"Po","before_placeholder":"P\u0159ed"},"numbers":{"all":"all","filter_button_text":"Filter","reset_button_text":"Reset","min_placeholder":"Min","max_placeholder":"Max"}},"eventlog":{"show_stacktrace":"Zobrazit stacktrace","hide_stacktrace":"Skr\u00fdt stacktrace","tabs":{"formatted":"Form\u00e1tov\u00e1no","raw":"P\u016fvodn\u00ed (raw)"},"editor":{"title":"Editor zdrojov\u00e9ho k\u00f3du","description":"V\u00e1\u0161 opera\u010dn\u00ed syst\u00e9m by m\u011bl b\u00fdt konfigurov\u00e1n tak, aby naslouchal jednomu z t\u011bchto sch\u00e9mat adres URL.","openWith":"Otev\u0159\u00edt v","remember_choice":"Zapamatovat si vybranou volbu pro tuto relaci","open":"Otev\u0159\u00edt","cancel":"Zru\u0161it"}}} + {"markdowneditor":{"formatting":"Form\u00e1tov\u00e1n\u00ed","quote":"Citace","code":"K\u00f3d","header1":"Nadpis 1","header2":"Nadpis 2","header3":"Nadpis 3","header4":"Nadpis 4","header5":"Nadpis 5","header6":"Nadpis 6","bold":"Tu\u010dn\u011b","italic":"Kurz\u00edvou","unorderedlist":"Ne\u010d\u00edslovan\u00fd seznam","orderedlist":"\u010c\u00edslovan\u00fd seznam","video":"Video","image":"Obr\u00e1zek","link":"Odkaz","horizontalrule":"Vlo\u017eit horizont\u00e1ln\u00ed linku","fullscreen":"Cel\u00e1 obrazovka","preview":"N\u00e1hled"},"mediamanager":{"insert_link":"Vlo\u017eit odkaz","insert_image":"Vlo\u017eit obr\u00e1zek","insert_video":"Vlo\u017eit video","insert_audio":"Vlo\u017eit zvuk","invalid_file_empty_insert":"Pros\u00edm vyberte soubor, na kter\u00fd se vlo\u017e\u00ed odkaz.","invalid_file_single_insert":"Vyberte jeden soubor.","invalid_image_empty_insert":"Vyberte soubor(y) pro vlo\u017een\u00ed.","invalid_video_empty_insert":"Vyberte video soubor pro vlo\u017een\u00ed.","invalid_audio_empty_insert":"Vyberte audio soubor pro vlo\u017een\u00ed."},"alert":{"confirm_button_text":"OK","cancel_button_text":"Zru\u0161it","widget_remove_confirm":"Odstranit widget?"},"datepicker":{"previousMonth":"P\u0159edchoz\u00ed m\u011bs\u00edc","nextMonth":"N\u00e1sleduj\u00edc\u00ed m\u011bs\u00edc","months":["Leden","\u00danor","B\u0159ezen","Duben","Kv\u011bten","\u010cerven","\u010cervenec","Srpen","Z\u00e1\u0159\u00ed","\u0158\u00edjen","Listopad","Prosinec"],"weekdays":["Ned\u011ble","Pond\u011bl\u00ed","\u00dater\u00fd","St\u0159eda","\u010ctvrtek","P\u00e1tek","Sobota"],"weekdaysShort":["Ne","Po","\u00dat","St","\u010ct","P\u00e1","So"]},"colorpicker":{"choose":"Ok"},"filter":{"group":{"all":"V\u0161e"},"scopes":{"apply_button_text":"Filtrovat","clear_button_text":"Zru\u0161it"},"dates":{"all":"V\u0161e","filter_button_text":"Filtrovat","reset_button_text":"Zru\u0161it","date_placeholder":"Datum","after_placeholder":"Po","before_placeholder":"P\u0159ed"},"numbers":{"all":"V\u0161e","filter_button_text":"Filtrovat","reset_button_text":"Zru\u0161it","min_placeholder":"Minimum","max_placeholder":"Maximum"}},"eventlog":{"show_stacktrace":"Zobrazit stacktrace","hide_stacktrace":"Skr\u00fdt stacktrace","tabs":{"formatted":"Form\u00e1tov\u00e1no","raw":"P\u016fvodn\u00ed (raw)"},"editor":{"title":"Editor zdrojov\u00e9ho k\u00f3du","description":"V\u00e1\u0161 opera\u010dn\u00ed syst\u00e9m by m\u011bl b\u00fdt konfigurov\u00e1n tak, aby naslouchal jednomu z t\u011bchto sch\u00e9mat adres URL.","openWith":"Otev\u0159\u00edt v","remember_choice":"Zapamatovat si vybranou volbu pro tuto relaci","open":"Otev\u0159\u00edt","cancel":"Zru\u0161it"}}} ); //! moment.js locale configuration v2.22.2 diff --git a/modules/system/assets/js/lang/lang.fr.js b/modules/system/assets/js/lang/lang.fr.js index 912c23504c..f383b27e58 100644 --- a/modules/system/assets/js/lang/lang.fr.js +++ b/modules/system/assets/js/lang/lang.fr.js @@ -5,62 +5,61 @@ if ($.oc === undefined) $.oc = {} if ($.oc.langMessages === undefined) $.oc.langMessages = {} $.oc.langMessages['fr'] = $.extend( $.oc.langMessages['fr'] || {}, - { "markdowneditor": { "formatting": "Formatage", "quote": "Citation", "code": "Code", "header1": "Ent\u00eate 1", "header2": "Ent\u00eate 2", "header3": "Ent\u00eate 3", "header4": "Ent\u00eate 4", "header5": "Ent\u00eate 5", "header6": "Ent\u00eate 6", "bold": "Gras", "italic": "Italique", "unorderedlist": "Liste non ordonn\u00e9e", "orderedlist": "Liste ordonn\u00e9e", "video": "Vid\u00e9o", "image": "Image", "link": "Lien", "horizontalrule": "Ins\u00e9rer la r\u00e8gle horizontalement", "fullscreen": "Plein \u00e9cran", "preview": "Aper\u00e7u" }, "mediamanager": { "insert_link": "Ins\u00e9rer un lien vers un fichier du gestionnaire de m\u00e9dia", "insert_image": "Ins\u00e9rer une image du gestionnaire de m\u00e9dia", "insert_video": "Ins\u00e9rer une vid\u00e9o du gestionnaire de m\u00e9dia", "insert_audio": "Ins\u00e9rer un document audio du gestionnaire de m\u00e9dia", "invalid_file_empty_insert": "Veuillez s\u00e9lectionner un fichier \u00e0 lier.", "invalid_file_single_insert": "Veuillez s\u00e9lectionner un seul fichier.", "invalid_image_empty_insert": "Veuillez s\u00e9lectionner au moins une image \u00e0 ins\u00e9rer.", "invalid_video_empty_insert": "Veuillez s\u00e9lectionner une vid\u00e9o \u00e0 ins\u00e9rer.", "invalid_audio_empty_insert": "Veuillez s\u00e9lectionner un document audio \u00e0 ins\u00e9rer." }, "alert": { "confirm_button_text": "OK", "cancel_button_text": "Annuler", "widget_remove_confirm": "Retirer ce widget ?" }, "datepicker": { "previousMonth": "Mois pr\u00e9c\u00e9dent", "nextMonth": "Mois suivant", "months": ["Janvier", "F\u00e9vrier", "Mars", "Avril", "Mai", "Juin", "Juillet", "Ao\u00fbt", "Septembre", "Octobre", "Novembre", "D\u00e9cembre"], "weekdays": ["Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"], "weekdaysShort": ["Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam"] }, "colorpicker": { "choose": "Ok" }, "filter": { "group": { "all": "tous" }, "scopes": { "apply_button_text": "Appliquer", "clear_button_text": "Annuler" }, "dates": { "all": "toute la p\u00e9riode", "filter_button_text": "Filtrer", "reset_button_text": "Effacer", "date_placeholder": "Date", "after_placeholder": "Apr\u00e8s le", "before_placeholder": "Avant le" }, "numbers": { "all": "tous", "filter_button_text": "Filtres", "reset_button_text": "R\u00e9initialiser", "min_placeholder": "Min", "max_placeholder": "Max" } }, "eventlog": { "show_stacktrace": "Afficher la pile d\u2019ex\u00e9cution", "hide_stacktrace": "Masquer la pile d\u2019ex\u00e9cution", "tabs": { "formatted": "Message format\u00e9", "raw": "Message brut" }, "editor": { "title": "S\u00e9lectionnez l\u2019\u00e9diteur de code source \u00e0 utiliser", "description": "L\u2019environnement de votre syst\u00e8me d\u2019exploitation doit \u00eatre configur\u00e9 pour ouvrir l\u2019un des sch\u00e9mas d\u2019URL ci-dessous.", "openWith": "Ouvrir avec", "remember_choice": "Se souvenir de la s\u00e9lection pour la dur\u00e9e de la session dans ce navigateur", "open": "Ouvrir", "cancel": "Annuler" } } } + {"markdowneditor":{"formatting":"Formatage","quote":"Citation","code":"Code","header1":"Ent\u00eate 1","header2":"Ent\u00eate 2","header3":"Ent\u00eate 3","header4":"Ent\u00eate 4","header5":"Ent\u00eate 5","header6":"Ent\u00eate 6","bold":"Gras","italic":"Italique","unorderedlist":"Liste non ordonn\u00e9e","orderedlist":"Liste ordonn\u00e9e","video":"Vid\u00e9o","image":"Image","link":"Lien","horizontalrule":"Ins\u00e9rer la r\u00e8gle horizontalement","fullscreen":"Plein \u00e9cran","preview":"Aper\u00e7u"},"mediamanager":{"insert_link":"Ins\u00e9rer un lien vers un fichier du gestionnaire de m\u00e9dia","insert_image":"Ins\u00e9rer une image du gestionnaire de m\u00e9dia","insert_video":"Ins\u00e9rer une vid\u00e9o du gestionnaire de m\u00e9dia","insert_audio":"Ins\u00e9rer un document audio du gestionnaire de m\u00e9dia","invalid_file_empty_insert":"Veuillez s\u00e9lectionner un fichier \u00e0 lier.","invalid_file_single_insert":"Veuillez s\u00e9lectionner un seul fichier.","invalid_image_empty_insert":"Veuillez s\u00e9lectionner au moins une image \u00e0 ins\u00e9rer.","invalid_video_empty_insert":"Veuillez s\u00e9lectionner une vid\u00e9o \u00e0 ins\u00e9rer.","invalid_audio_empty_insert":"Veuillez s\u00e9lectionner un document audio \u00e0 ins\u00e9rer."},"alert":{"confirm_button_text":"OK","cancel_button_text":"Annuler","widget_remove_confirm":"Retirer ce widget ?"},"datepicker":{"previousMonth":"Mois pr\u00e9c\u00e9dent","nextMonth":"Mois suivant","months":["Janvier","F\u00e9vrier","Mars","Avril","Mai","Juin","Juillet","Ao\u00fbt","Septembre","Octobre","Novembre","D\u00e9cembre"],"weekdays":["Dimanche","Lundi","Mardi","Mercredi","Jeudi","Vendredi","Samedi"],"weekdaysShort":["Dim","Lun","Mar","Mer","Jeu","Ven","Sam"]},"colorpicker":{"choose":"Ok"},"filter":{"group":{"all":"tous"},"scopes":{"apply_button_text":"Appliquer","clear_button_text":"Annuler"},"dates":{"all":"toute la p\u00e9riode","filter_button_text":"Filtrer","reset_button_text":"Effacer","date_placeholder":"Date","after_placeholder":"Apr\u00e8s le","before_placeholder":"Avant le"},"numbers":{"all":"tous","filter_button_text":"Filtres","reset_button_text":"R\u00e9initialiser","min_placeholder":"Min","max_placeholder":"Max"}},"eventlog":{"show_stacktrace":"Afficher la pile d\u2019ex\u00e9cution","hide_stacktrace":"Masquer la pile d\u2019ex\u00e9cution","tabs":{"formatted":"Message format\u00e9","raw":"Message brut"},"editor":{"title":"S\u00e9lectionnez l\u2019\u00e9diteur de code source \u00e0 utiliser","description":"L\u2019environnement de votre syst\u00e8me d\u2019exploitation doit \u00eatre configur\u00e9 pour ouvrir l\u2019un des sch\u00e9mas d\u2019URL ci-dessous.","openWith":"Ouvrir avec","remember_choice":"Se souvenir de la s\u00e9lection pour la dur\u00e9e de la session dans ce navigateur","open":"Ouvrir","cancel":"Annuler"}}} ); //! moment.js locale configuration v2.22.2 -; (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' - && typeof require === 'function' ? factory(require('../moment')) : - typeof define === 'function' && define.amd ? define(['../moment'], factory) : - factory(global.moment) -}(this, (function (moment) { - 'use strict'; +;(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' + && typeof require === 'function' ? factory(require('../moment')) : + typeof define === 'function' && define.amd ? define(['../moment'], factory) : + factory(global.moment) +}(this, (function (moment) { 'use strict'; var fr = moment.defineLocale('fr', { - months: 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_'), - monthsShort: 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split('_'), - monthsParseExact: true, - weekdays: 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'), - weekdaysShort: 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'), - weekdaysMin: 'di_lu_ma_me_je_ve_sa'.split('_'), - weekdaysParseExact: true, - longDateFormat: { - LT: 'HH:mm', - LTS: 'HH:mm:ss', - L: 'DD/MM/YYYY', - LL: 'D MMMM YYYY', - LLL: 'D MMMM YYYY HH:mm', - LLLL: 'dddd D MMMM YYYY HH:mm' + months : 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_'), + monthsShort : 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split('_'), + monthsParseExact : true, + weekdays : 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'), + weekdaysShort : 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'), + weekdaysMin : 'di_lu_ma_me_je_ve_sa'.split('_'), + weekdaysParseExact : true, + longDateFormat : { + LT : 'HH:mm', + LTS : 'HH:mm:ss', + L : 'DD/MM/YYYY', + LL : 'D MMMM YYYY', + LLL : 'D MMMM YYYY HH:mm', + LLLL : 'dddd D MMMM YYYY HH:mm' }, - calendar: { - sameDay: '[Aujourd’hui à] LT', - nextDay: '[Demain à] LT', - nextWeek: 'dddd [à] LT', - lastDay: '[Hier à] LT', - lastWeek: 'dddd [dernier à] LT', - sameElse: 'L' + calendar : { + sameDay : '[Aujourd’hui à] LT', + nextDay : '[Demain à] LT', + nextWeek : 'dddd [à] LT', + lastDay : '[Hier à] LT', + lastWeek : 'dddd [dernier à] LT', + sameElse : 'L' }, - relativeTime: { - future: 'dans %s', - past: 'il y a %s', - s: 'quelques secondes', - ss: '%d secondes', - m: 'une minute', - mm: '%d minutes', - h: 'une heure', - hh: '%d heures', - d: 'un jour', - dd: '%d jours', - M: 'un mois', - MM: '%d mois', - y: 'un an', - yy: '%d ans' + relativeTime : { + future : 'dans %s', + past : 'il y a %s', + s : 'quelques secondes', + ss : '%d secondes', + m : 'une minute', + mm : '%d minutes', + h : 'une heure', + hh : '%d heures', + d : 'un jour', + dd : '%d jours', + M : 'un mois', + MM : '%d mois', + y : 'un an', + yy : '%d ans' }, dayOfMonthOrdinalParse: /\d{1,2}(er|)/, - ordinal: function (number, period) { + ordinal : function (number, period) { switch (period) { // TODO: Return 'e' when day of month > 1. Move this case inside // block for masculine words below. @@ -82,9 +81,9 @@ $.oc.langMessages['fr'] = $.extend( return number + (number === 1 ? 're' : 'e'); } }, - week: { - dow: 1, // Monday is the first day of the week. - doy: 4 // The week that contains Jan 4th is the first week of the year. + week : { + dow : 1, // Monday is the first day of the week. + doy : 4 // The week that contains Jan 4th is the first week of the year. } }); diff --git a/modules/system/assets/js/lang/lang.sl.js b/modules/system/assets/js/lang/lang.sl.js index 0caba5199d..cd1b00afdd 100644 --- a/modules/system/assets/js/lang/lang.sl.js +++ b/modules/system/assets/js/lang/lang.sl.js @@ -11,218 +11,103 @@ $.oc.langMessages['sl'] = $.extend( //! moment.js locale configuration v2.22.2 ;(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' - && typeof require === 'function' ? factory(require('../moment')) : - typeof define === 'function' && define.amd ? define(['../moment'], factory) : - factory(global.moment) + typeof exports === 'object' && typeof module !== 'undefined' + && typeof require === 'function' ? factory(require('../moment')) : + typeof define === 'function' && define.amd ? define(['../moment'], factory) : + factory(global.moment) }(this, (function (moment) { 'use strict'; - function translate(number, withoutSuffix, key, isFuture) { + + function processRelativeTime(number, withoutSuffix, key, isFuture) { var result = number + ' '; switch (key) { - case 's': // a few seconds / in a few seconds / a few seconds ago - return (withoutSuffix || isFuture) ? 'nekaj sekund' : 'nekaj sekundami'; - case 'ss': // 9 seconds / in 9 seconds / 9 seconds ago - if (withoutSuffix) { - if (number == 1) { - return result + 'sekunda'; - } else if (number == 2) { - return result + 'sekundi'; - } else if (number == 3 || number == 4) { - return result + 'sekunde'; - } else { - return result + 'sekund'; - } - } else if (isFuture) { - if (number == 1) { - return result + 'sekundo'; - } else if (number == 2) { - return result + 'sekundi'; - } else if (number == 3 || number == 4) { - return result + 'sekunde'; - } else { - return result + 'sekund'; - } + case 's': + return withoutSuffix || isFuture ? 'nekaj sekund' : 'nekaj sekundami'; + case 'ss': + if (number === 1) { + result += withoutSuffix ? 'sekundo' : 'sekundi'; + } else if (number === 2) { + result += withoutSuffix || isFuture ? 'sekundi' : 'sekundah'; + } else if (number < 5) { + result += withoutSuffix || isFuture ? 'sekunde' : 'sekundah'; } else { - if (number == 1) { - return result + 'sekundo'; - } else if (number == 2) { - return result + 'sekundama'; - } else { - return result + 'sekundami'; - } + result += withoutSuffix || isFuture ? 'sekund' : 'sekund'; } - break; - case 'm': // a minute / in a minute / a minute ago - return withoutSuffix ? 'minuta' : 'minuto'; - case 'mm': // 9 minutes / in 9 minutes / 9 minutes ago - if (withoutSuffix) { - if (number == 1) { - return result + 'minuta'; - } else if (number == 2) { - return result + 'minuti'; - } else if (number == 3 || number == 4) { - return result + 'minute'; - } else { - return result + 'minut'; - } - } else if (isFuture) { - if (number == 1) { - return result + 'minuto'; - } else if (number == 2) { - return result + 'minuti'; - } else if (number == 3 || number == 4) { - return result + 'minute'; - } else { - return result + 'minut'; - } + return result; + case 'm': + return withoutSuffix ? 'ena minuta' : 'eno minuto'; + case 'mm': + if (number === 1) { + result += withoutSuffix ? 'minuta' : 'minuto'; + } else if (number === 2) { + result += withoutSuffix || isFuture ? 'minuti' : 'minutama'; + } else if (number < 5) { + result += withoutSuffix || isFuture ? 'minute' : 'minutami'; } else { - if (number == 1) { - return result + 'minuto'; - } else if (number == 2) { - return result + 'minutama'; - } else { - return result + 'minutami'; - } + result += withoutSuffix || isFuture ? 'minut' : 'minutami'; } - break; - case 'h': // an hour / in an hour / an hour ago - return withoutSuffix ? 'ura' : 'eno uro'; - case 'hh': // 9 hours / in 9 hours / 9 hours ago - if (withoutSuffix) { - if (number == 1) { - return result + 'ura'; - } else if (number == 2) { - return result + 'uri'; - } else if (number == 3 || number == 4) { - return result + 'ure'; - } else { - return result + 'ur'; - } - } else if (isFuture) { - if (number == 1) { - return result + 'uro'; - } else if (number == 2) { - return result + 'uri'; - } else if (number == 3 || number == 4) { - return result + 'ure'; - } else { - return result + 'ur'; - } + return result; + case 'h': + return withoutSuffix ? 'ena ura' : 'eno uro'; + case 'hh': + if (number === 1) { + result += withoutSuffix ? 'ura' : 'uro'; + } else if (number === 2) { + result += withoutSuffix || isFuture ? 'uri' : 'urama'; + } else if (number < 5) { + result += withoutSuffix || isFuture ? 'ure' : 'urami'; } else { - if (number == 1) { - return result + 'uro'; - } else if (number == 2) { - return result + 'urama'; - } else { - return result + 'urami'; - } + result += withoutSuffix || isFuture ? 'ur' : 'urami'; } - break; - case 'd': // a day / in a day / a day ago - return withoutSuffix ? 'dan' : (isFuture ? 'en dan' : 'enim dnem'); - case 'dd': // 9 days / in 9 days / 9 days ago - if (withoutSuffix) { - if (number == 1) { - return result + 'dan'; - } else if (number == 2) { - return result + 'dneva'; - } else if (number == 3 || number == 4) { - return result + 'dnevi'; - } else { - return result + 'dni'; - } - } else if (isFuture) { - if (number == 1) { - return result + 'dan'; - } else { - return result + 'dni'; - } + return result; + case 'd': + return withoutSuffix || isFuture ? 'en dan' : 'enim dnem'; + case 'dd': + if (number === 1) { + result += withoutSuffix || isFuture ? 'dan' : 'dnem'; + } else if (number === 2) { + result += withoutSuffix || isFuture ? 'dni' : 'dnevoma'; } else { - if (number == 1) { - return result + 'dnevom'; - } else if (number == 2) { - return result + 'dnevoma'; - } else { - return result + 'dnevi'; - } + result += withoutSuffix || isFuture ? 'dni' : 'dnevi'; } - break; - case 'M': // a month / in a month / a month ago - return withoutSuffix ? 'mesec' : (isFuture ? 'en mesec' : 'enim mesecem'); - case 'MM': // 9 months / in 9 months / 9 months ago - if (withoutSuffix) { - if (number == 1) { - return result + 'mesec'; - } else if (number == 2) { - return result + 'meseca'; - } else if (number == 3 || number == 4) { - return result + 'meseci'; - } else { - return result + 'mesecev'; - } - } else if (isFuture) { - if (number == 1) { - return result + 'mesec'; - } else if (number == 2) { - return result + 'meseca'; - } else if (number == 3 || number == 4) { - return result + 'mesece'; - } else { - return result + 'mesecev'; - } + return result; + case 'M': + return withoutSuffix || isFuture ? 'en mesec' : 'enim mesecem'; + case 'MM': + if (number === 1) { + result += withoutSuffix || isFuture ? 'mesec' : 'mesecem'; + } else if (number === 2) { + result += withoutSuffix || isFuture ? 'meseca' : 'mesecema'; + } else if (number < 5) { + result += withoutSuffix || isFuture ? 'mesece' : 'meseci'; } else { - if (number == 1) { - return result + 'mesecom'; - } else if (number == 2) { - return result + 'mesecema'; - } else { - return result + 'meseci'; - } + result += withoutSuffix || isFuture ? 'mesecev' : 'meseci'; } - break; - case 'y': // a year / in a year / a year ago - return withoutSuffix ? 'leto' : (isFuture ? 'eno leto' : 'enim letom'); - case 'yy': // 9 years / in 9 years / 9 years ago - if (withoutSuffix) { - if (number == 1) { - return result + 'leto'; - } else if (number == 2) { - return result + 'leti'; - } else if (number == 3 || number == 4) { - return result + 'leta'; - } else { - return result + 'let'; - } - } else if (isFuture) { - if (number == 1) { - return result + 'leto'; - } else if (number == 2) { - return result + 'leti'; - } else if (number == 3 || number == 4) { - return result + 'leta'; - } else { - return result + 'let'; - } + return result; + case 'y': + return withoutSuffix || isFuture ? 'eno leto' : 'enim letom'; + case 'yy': + if (number === 1) { + result += withoutSuffix || isFuture ? 'leto' : 'letom'; + } else if (number === 2) { + result += withoutSuffix || isFuture ? 'leti' : 'letoma'; + } else if (number < 5) { + result += withoutSuffix || isFuture ? 'leta' : 'leti'; } else { - if (number == 1) { - return result + 'letom'; - } else if (number == 2) { - return result + 'letoma'; - } else { - return result + 'leti'; - } + result += withoutSuffix || isFuture ? 'let' : 'leti'; } - break; + return result; } } var sl = moment.defineLocale('sl', { months : 'januar_februar_marec_april_maj_junij_julij_avgust_september_oktober_november_december'.split('_'), - monthsShort : 'jan_feb_mar_apr_maj_jun_jul_avg_sep_okt_nov_dec'.split('_'), - weekdays : 'nedelja_ponedeljek_torek_sreda_\u010detrtek_petek_sobota'.split('_'), - weekdaysShort : 'ned_pon_tor_sre_\u010det_pet_sob'.split('_'), - weekdaysMin : 'ne_po_to_sr_\u010de_pe_so'.split('_'), + monthsShort : 'jan._feb._mar._apr._maj._jun._jul._avg._sep._okt._nov._dec.'.split('_'), + monthsParseExact: true, + weekdays : 'nedelja_ponedeljek_torek_sreda_četrtek_petek_sobota'.split('_'), + weekdaysShort : 'ned._pon._tor._sre._čet._pet._sob.'.split('_'), + weekdaysMin : 'ne_po_to_sr_če_pe_so'.split('_'), + weekdaysParseExact : true, longDateFormat : { LT : 'H:mm', LTS : 'H:mm:ss', @@ -232,64 +117,63 @@ $.oc.langMessages['sl'] = $.extend( LLLL : 'dddd, D. MMMM YYYY H:mm' }, calendar : { - sameDay : '[danes ob] LT', - nextDay : '[jutri ob] LT', - nextWeek: function () { + sameDay : '[danes ob] LT', + nextDay : '[jutri ob] LT', + + nextWeek : function () { switch (this.day()) { case 0: - return '[v nedeljo ob] LT'; + return '[v] [nedeljo] [ob] LT'; + case 3: + return '[v] [sredo] [ob] LT'; + case 6: + return '[v] [soboto] [ob] LT'; case 1: case 2: - return '[v] dddd [ob] LT'; - case 3: - return '[v sredo ob] LT'; case 4: case 5: return '[v] dddd [ob] LT'; - case 6: - return '[v soboto ob] LT'; } }, - lastDay : '[včeraj ob] LT', - lastWeek: function () { + lastDay : '[včeraj ob] LT', + lastWeek : function () { switch (this.day()) { case 0: - return '[prej\u0161njo nedeljo ob] LT'; + return '[prejšnjo] [nedeljo] [ob] LT'; + case 3: + return '[prejšnjo] [sredo] [ob] LT'; + case 6: + return '[prejšnjo] [soboto] [ob] LT'; case 1: case 2: - return '[prej\u0161nji] dddd [ob] LT'; - case 3: - return '[prej\u0161njo sredo ob] LT'; case 4: case 5: - return '[prej\u0161nji] dddd [ob] LT'; - case 6: - return '[prej\u0161njo soboto ob] LT'; + return '[prejšnji] dddd [ob] LT'; } }, sameElse : 'L' }, relativeTime : { - future : '\u010dez %s', - past : 'pred %s', - s : translate, - ss : translate, - m : translate, - mm : translate, - h : translate, - hh : translate, - d : translate, - dd : translate, - M : translate, - MM : translate, - y : translate, - yy : translate + future : 'čez %s', + past : 'pred %s', + s : processRelativeTime, + ss : processRelativeTime, + m : processRelativeTime, + mm : processRelativeTime, + h : processRelativeTime, + hh : processRelativeTime, + d : processRelativeTime, + dd : processRelativeTime, + M : processRelativeTime, + MM : processRelativeTime, + y : processRelativeTime, + yy : processRelativeTime }, dayOfMonthOrdinalParse: /\d{1,2}\./, ordinal : '%d.', week : { dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. + doy : 7 // The week that contains Jan 1st is the first week of the year. } }); From 2eeb06ebf216e3e8507da2a8ee2ee1cd2f04c85a Mon Sep 17 00:00:00 2001 From: Ben Thomson Date: Thu, 12 Dec 2019 18:44:10 +0800 Subject: [PATCH 150/157] More strict checking of addItem request for child repeaters (#4814) Similarly named repeater fields being used in viewBag variables were being assigned aliases which succeeded the `strpos` check on line 407. This will more clearly look for a child repeater form and index. Fixes #4808 --- modules/backend/formwidgets/Repeater.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/backend/formwidgets/Repeater.php b/modules/backend/formwidgets/Repeater.php index e25df461fa..f9fa3a6fb2 100644 --- a/modules/backend/formwidgets/Repeater.php +++ b/modules/backend/formwidgets/Repeater.php @@ -98,7 +98,7 @@ class Repeater extends FormWidgetBase public function init() { $this->prompt = Lang::get('backend::lang.repeater.add_new_item'); - + $this->fillFromConfig([ 'form', 'prompt', @@ -404,15 +404,15 @@ protected function checkAddItemRequest() if ($this->alias === $widgetName) { // This repeater has made the AJAX request self::$onAddItemCalled = true; - } else if (strpos($widgetName, $this->alias) === 0) { + } else if (strpos($widgetName, $this->alias . 'Form') === 0) { // A child repeater has made the AJAX request // Get index from AJAX handler $handlerSuffix = str_replace($this->alias . 'Form', '', $widgetName); - preg_match('/^[0-9]+/', $handlerSuffix, $matches); - - $this->childAddItemCalled = true; - $this->childIndexCalled = (int) $matches[0]; + if (preg_match('/^[0-9]+/', $handlerSuffix, $matches)) { + $this->childAddItemCalled = true; + $this->childIndexCalled = (int) $matches[0]; + } } } From 8c5634d016ba9998bc1caa3ae6aeb890f3c21c2a Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Thu, 12 Dec 2019 22:02:39 +1100 Subject: [PATCH 151/157] Exception handling $widget->secondaryTabs['fields'] may not always be present --- modules/cms/controllers/Index.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/cms/controllers/Index.php b/modules/cms/controllers/Index.php index 4f9d2e78d0..07af395c13 100644 --- a/modules/cms/controllers/Index.php +++ b/modules/cms/controllers/Index.php @@ -68,7 +68,12 @@ public function __construct() if (!$widget->model instanceof CmsCompoundObject) { return; } - if (key_exists('code', $widget->secondaryTabs['fields']) && CmsHelpers::safeModeEnabled()) { + + if (empty($widget->secondaryTabs['fields'])) { + return; + } + + if (array_key_exists('code', $widget->secondaryTabs['fields']) && CmsHelpers::safeModeEnabled()) { $widget->secondaryTabs['fields']['safemode_notice']['hidden'] = false; $widget->secondaryTabs['fields']['code']['readOnly'] = true; }; From 2a94d7f2b5a433b9f0a3d922bfb1a2be9624f4f5 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Thu, 12 Dec 2019 22:47:07 +1100 Subject: [PATCH 152/157] Add premium support, contributor badges + minor changes --- README.md | 64 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index de8b75333f..97f3c6d79f 100644 --- a/README.md +++ b/README.md @@ -29,52 +29,62 @@ php artisan october:install ## Learning October -The best place to learn October is by [reading the documentation](https://octobercms.com/docs) or [following some tutorials](https://octobercms.com/support/articles/tutorials). +The best place to learn October is by [reading the documentation](https://octobercms.com/docs), [watching some screencasts](https://octobercms.com/support/topic/screencast) or [following some tutorials](https://octobercms.com/support/articles/tutorials). -You may also watch these introductory videos for [beginners](https://vimeo.com/79963873) and [advanced users](https://vimeo.com/172202661). There is also the excellent video series by [Watch & Learn](https://watch-learn.com/series/making-websites-with-october-cms). +You may also watch these introductory videos for [beginners](https://vimeo.com/79963873) and [advanced users](https://vimeo.com/172202661). -## Contributing +## Development Team -Before sending a Pull Request, be sure to review the [Contributing Guidelines](.github/CONTRIBUTING.md) first. +October was created by [Alexey Bobkov](http://ca.linkedin.com/pub/aleksey-bobkov/2b/ba0/232) and [Samuel Georges](https://www.linkedin.com/in/samuel-georges-0a964131/), who both continue to develop the platform. -### Help and support this project +The maintenance of October is lead by [Luke Towers](https://luketowers.ca/), along with many wonderful people that dedicate their time to help support and grow the community. -You can also help the project by reviewing and testing open Pull Requests with the "**Status: Testing Needed**" tag. -[Read more...](https://github.com/octobercms/october/blob/master/.github/CONTRIBUTING.md#testing-pull-requests) +
  • {{ body|md_safe }} From 16f7560a39141101ef713c8e2c1d5793a37a78cf Mon Sep 17 00:00:00 2001 From: Luke Towers Date: Tue, 15 Oct 2019 16:46:02 -0600 Subject: [PATCH 074/157] Added support for mode: switch to the PermissionEditor formwidget --- modules/backend/ServiceProvider.php | 1 + .../backend/formwidgets/PermissionEditor.php | 30 ++-- .../assets/css/permissioneditor.css | 132 ++++-------------- .../assets/less/permissioneditor.less | 7 +- .../partials/_permissioneditor.htm | 86 ++++++++---- 5 files changed, 115 insertions(+), 141 deletions(-) diff --git a/modules/backend/ServiceProvider.php b/modules/backend/ServiceProvider.php index 28c62f9033..60ef1b9e0a 100644 --- a/modules/backend/ServiceProvider.php +++ b/modules/backend/ServiceProvider.php @@ -77,6 +77,7 @@ protected function registerAssetBundles() $combiner->registerBundle('~/modules/backend/formwidgets/nestedform/assets/less/nestedform.less'); $combiner->registerBundle('~/modules/backend/formwidgets/richeditor/assets/js/build-plugins.js'); $combiner->registerBundle('~/modules/backend/formwidgets/colorpicker/assets/less/colorpicker.less'); + $combiner->registerBundle('~/modules/backend/formwidgets/permissioneditor/assets/less/permissioneditor.less'); /* * Rich Editor is protected by DRM diff --git a/modules/backend/formwidgets/PermissionEditor.php b/modules/backend/formwidgets/PermissionEditor.php index 014e523b3b..72842a8113 100644 --- a/modules/backend/formwidgets/PermissionEditor.php +++ b/modules/backend/formwidgets/PermissionEditor.php @@ -7,6 +7,22 @@ * User/group permission editor * This widget is used by the system internally on the System / Administrators pages. * + * Available Modes: + * - radio: Default mode, used by user-level permissions. + * Provides three-state control over each available permission. States are + * -1: Explicitly deny the permission + * 0: Inherit the permission's value from a parent source (User inherits from Role) + * 1: Explicitly grant the permission + * - checkbox: Used to define permissions for roles. Intended to define a base of what permissions are available + * Provides two state control over each available permission. States are + * 1: Explicitly allow the permission + * null: If the checkbox is not ticked, the permission will not be sent to the server and will not be stored. + * This is interpreted as the permission not being present and thus not allowed + * - switch: Used to define overriding permissions in a simpler UX than the radio. + * Provides two state control over each available permission. States are + * 1: Explicitly allow the permission + * -1: Explicitly deny the permission + * * @package october\backend * @author Alexey Bobkov, Samuel Georges */ @@ -14,7 +30,10 @@ class PermissionEditor extends FormWidgetBase { protected $user; - public $mode; + /** + * @var string Mode to display the permission editor with. Available options: radio, checkbox, switch + */ + public $mode = 'radio'; /** * @inheritDoc @@ -51,7 +70,7 @@ public function prepareVars() $permissionsData = []; } - $this->vars['checkboxMode'] = $this->getControlMode() === 'checkbox'; + $this->vars['mode'] = $this->mode; $this->vars['permissions'] = $this->getFilteredPermissions(); $this->vars['baseFieldName'] = $this->getFieldName(); $this->vars['permissionsData'] = $permissionsData; @@ -79,11 +98,6 @@ protected function loadAssets() $this->addJs('js/permissioneditor.js', 'core'); } - protected function getControlMode() - { - return strlen($this->mode) ? $this->mode : 'radio'; - } - /** * Returns a safely parsed set of permissions, ensuring the user cannot elevate * their own permissions or permissions of another user above their own. @@ -117,7 +131,7 @@ protected function getSaveValueSecure($value) /** * Returns the available permissions; removing those that the logged-in user does not have access to * - * @return array The permissions that the logged-in user does have access to + * @return array The permissions that the logged-in user does have access to ['permission-tab' => $arrayOfAllowedPermissionObjects] */ protected function getFilteredPermissions() { diff --git a/modules/backend/formwidgets/permissioneditor/assets/css/permissioneditor.css b/modules/backend/formwidgets/permissioneditor/assets/css/permissioneditor.css index ee2bce90ab..c1316dc40e 100644 --- a/modules/backend/formwidgets/permissioneditor/assets/css/permissioneditor.css +++ b/modules/backend/formwidgets/permissioneditor/assets/css/permissioneditor.css @@ -1,110 +1,40 @@ -.permissioneditor { - position: relative; - margin: 0 -20px; -} -.permissioneditor.control-disabled .permissions-overlay { - position: absolute; - left: 0; - top: 0; - width: 100%; - height: 100%; - background: rgba(255, 255, 255, 0.01); - cursor: not-allowed; -} -.permissioneditor.control-disabled table { - opacity: 0.5; - filter: alpha(opacity=50); -} -.permissioneditor table { - width: 100%; -} -.permissioneditor table th { - padding: 30px 4px 8px 4px; - color: #2a3e51; - font-weight: normal; - border-bottom: 1px solid #dbe1e3; -} -.permissioneditor table th.tab { - font-size: 13px; -} -.permissioneditor table th.permission-type { - text-transform: uppercase; - font-size: 11px; - text-align: center; -} -.permissioneditor table td { - padding: 10px 4px; - vertical-align: top; - border-bottom: 1px solid #ecf0f1; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} -.permissioneditor table td.permission-value { - text-align: center; -} -.permissioneditor table td.permission-name { - font-size: 13px; - cursor: pointer; - color: #777777; -} -.permissioneditor table td p.comment { - margin-top: 5px; - margin-bottom: 0; -} -.permissioneditor table td p.comment:empty { - display: none; -} -.permissioneditor table tr:hover td { - background: #4da7e8; -} -.permissioneditor table tr:hover td.permission-name { - color: #ffffff !important; -} +.permissioneditor {position:relative;margin:0 -20px} +.permissioneditor.control-disabled .permissions-overlay {position:absolute;left:0;top:0;width:100%;height:100%;background:rgba(255,255,255,0.01);cursor:not-allowed} +.permissioneditor.control-disabled table {opacity:0.5;filter:alpha(opacity=50)} +.permissioneditor table {width:100%} +.permissioneditor table th {padding:30px 4px 8px 4px;color:#2a3e51;font-weight:normal;border-bottom:1px solid #dbe1e3} +.permissioneditor table th.tab {font-size:13px} +.permissioneditor table th.permission-type {text-transform:uppercase;font-size:11px;text-align:center} +.permissioneditor table td {padding:10px 4px;vertical-align:top;border-bottom:1px solid #ecf0f1;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none} +.permissioneditor table td.permission-value {text-align:center} +.permissioneditor table td.permission-name {font-size:13px;cursor:pointer;color:#777} +.permissioneditor table td p.comment {margin-top:5px;margin-bottom:0} +.permissioneditor table td p.comment:empty {display:none} +.permissioneditor table tr:hover td {background:#4ea5e0} +.permissioneditor table tr:hover td.permission-name {color:#fff !important} .permissioneditor table th:first-child, -.permissioneditor table td:first-child { - padding-left: 20px; -} +.permissioneditor table td:first-child {padding-left:20px} .permissioneditor table th:last-child, -.permissioneditor table td:last-child { - padding-right: 5px; -} +.permissioneditor table td:last-child {padding-right:5px} .permissioneditor table .custom-radio, -.permissioneditor table .custom-checkbox { - display: inline-block; - padding-left: 0; -} +.permissioneditor table .custom-checkbox, +.permissioneditor table .custom-switch {display:inline-block;padding-left:0} .permissioneditor table .custom-radio, .permissioneditor table .custom-checkbox, +.permissioneditor table .custom-switch, .permissioneditor table .custom-radio label, -.permissioneditor table .custom-checkbox label { - margin-bottom: 0; -} +.permissioneditor table .custom-checkbox label, +.permissioneditor table .custom-switch label {margin-bottom:0} .permissioneditor table .custom-radio label, -.permissioneditor table .custom-checkbox label { - padding: 0 0 0 14px; - margin: 0; - top: 0; -} +.permissioneditor table .custom-checkbox label, +.permissioneditor table .custom-switch label {padding:0 0 0 14px;margin:0;top:0} .permissioneditor table .custom-radio label span, -.permissioneditor table .custom-checkbox label span { - text-indent: -10000em; - display: block; -} +.permissioneditor table .custom-checkbox label span, +.permissioneditor table .custom-switch label span {text-indent:-10000em;display:block} .permissioneditor table .custom-radio label:before, -.permissioneditor table .custom-checkbox label:before { - margin-right: 0; -} -.permissioneditor table tr:last-child td { - border-bottom: none; -} -.permissioneditor table tr:first-child th { - padding-top: 0; -} -.permissioneditor table tr.disabled td.permission-name { - color: #AAA; -} -.permissioneditor table tr.last-section-row td { - border-bottom: none; -} +.permissioneditor table .custom-checkbox label:before, +.permissioneditor table .custom-switch label:before {margin-right:0} +.permissioneditor table tr:last-child td {border-bottom:none} +.permissioneditor table tr:first-child th {padding-top:0} +.permissioneditor table tr.disabled td.permission-name {color:#AAA} +.permissioneditor table tr.last-section-row td {border-bottom:none} \ No newline at end of file diff --git a/modules/backend/formwidgets/permissioneditor/assets/less/permissioneditor.less b/modules/backend/formwidgets/permissioneditor/assets/less/permissioneditor.less index c5f575c079..956af038b0 100644 --- a/modules/backend/formwidgets/permissioneditor/assets/less/permissioneditor.less +++ b/modules/backend/formwidgets/permissioneditor/assets/less/permissioneditor.less @@ -31,7 +31,7 @@ padding: 30px 4px 8px 4px; color: @color-label; font-weight: normal; - border-bottom: 1px solid @color-permissioneditor-section-border; + border-bottom: 1px solid @color-permissioneditor-section-border; &.tab { font-size: @font-size-base - 1; @@ -47,7 +47,7 @@ td { padding: 10px 4px; vertical-align: top; - border-bottom: 1px solid @color-permissioneditor-permission-border; + border-bottom: 1px solid @color-permissioneditor-permission-border; .user-select(none); &.permission-value{ @@ -91,7 +91,8 @@ } .custom-radio, - .custom-checkbox { + .custom-checkbox, + .custom-switch { display: inline-block;; padding-left: 0; diff --git a/modules/backend/formwidgets/permissioneditor/partials/_permissioneditor.htm b/modules/backend/formwidgets/permissioneditor/partials/_permissioneditor.htm index 1284a6c592..2060a21ab6 100644 --- a/modules/backend/formwidgets/permissioneditor/partials/_permissioneditor.htm +++ b/modules/backend/formwidgets/permissioneditor/partials/_permissioneditor.htm @@ -3,16 +3,18 @@ mode === 'radio'); ?> $tabPermissions): ?>
    label)) ?> -

    comment)) ?>

    - + + mode === 'radio'): ?> +
    Allow
    - -
    - - > - - -
    - -
    Deny
    + + + + +
    + + > + + +
    +
    + + + + + + +
    Luke Towers
    Luke Towers
    Ben Thomson
    Ben Thomson
    Denis Denisov
    Denis Denisov
    Marc Jauvin
    Marc Jauvin
    -## Coding standards +## Foundation library -Please follow the following guides and code standards: +The CMS uses [Laravel](https://laravel.com) as a foundation PHP framework. -* [PSR 4 Coding Standards](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md) -* [PSR 2 Coding Style Guide](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) -* [PSR 1 Coding Standards](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md) +## Contact -## Code of Conduct +You can communicate with us using the following mediums: -In order to ensure that the OctoberCMS community is welcoming to all, please review and abide by the [Code of Conduct](CODE_OF_CONDUCT.md). +* [Follow us on Twitter](https://twitter.com/octobercms) for announcements and updates. +* [Follow us on Facebook](https://facebook.com/octobercms) for announcements and updates. +* [Join the Official Forum](https://octobercms.com/forum) to engage with the community. +* [Join us on Discord](https://octobercms.com/chat) to chat with us. -## Security Vulnerabilities +### Premium Support -Please review [our security policy](https://github.com/octobercms/october/security/policy) on how to report security vulnerabilities. +October CMS can provide premium support for a monthly fee. Find out more via the [Premium Support Program](https://octobercms.com/premium-support). -## Development Team +## Contributing -October was created by [Alexey Bobkov](http://ca.linkedin.com/pub/aleksey-bobkov/2b/ba0/232) and [Samuel Georges](https://www.linkedin.com/in/samuel-georges-0a964131/). The core maintainer is [Luke Towers](https://luketowers.ca/) and other maintainers include [Ben Thomson](https://github.com/bennothommo) and [Denis Denisov](https://github.com/w20k). +Before sending or reviewing Pull Requests, be sure to review the [Contributing Guidelines](.github/CONTRIBUTING.md) first. -## Foundation library +### Coding standards -The CMS uses [Laravel](https://laravel.com) as a foundation PHP framework. +Please follow the following guides and code standards: -## Contact +* [PSR 4 Coding Standards](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md) +* [PSR 2 Coding Style Guide](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) +* [PSR 1 Coding Standards](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md) -You can communicate with us using the following mediums: +### Code of Conduct -* [Follow us on Twitter](https://twitter.com/octobercms) for announcements and updates. -* [Follow us on Facebook](https://facebook.com/octobercms) for announcements and updates. -* [Join us on Slack](https://octobercms-slack.herokuapp.com/) to chat with us. -* [Join us on IRC](https://octobercms.com/chat) to chat with us. +In order to ensure that the October CMS community is welcoming to all, please review and abide by the [Code of Conduct](CODE_OF_CONDUCT.md). ## License -The OctoberCMS platform is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). +The October CMS platform is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). + +## Security Vulnerabilities + +Please review [our security policy](https://github.com/octobercms/october/security/policy) on how to report security vulnerabilities. From b5ad7d449130f5482564fd6172009794253cb113 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Thu, 12 Dec 2019 22:48:14 +1100 Subject: [PATCH 153/157] Typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 97f3c6d79f..eafabf24e8 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ The maintenance of October is lead by [Luke Towers](https://luketowers.ca/), alo
    Luke Towers
    Luke Towers
    Ben Thomson
    Ben Thomson
    Denis Denisov
    Denis Denisov
    Denis Denisov
    Denis Denisov
    Marc Jauvin
    Marc Jauvin
    From 65908ba15dc74a88f42ae6981fa34caa26fcab3b Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Fri, 13 Dec 2019 21:34:59 +1100 Subject: [PATCH 154/157] Move placeholder upon mouse scroll This is one step closer to fixing the sorting issues when a scrollbar is present. It still doesn't quite fix the issue, still need to find a way to get the container dimensions to update Refs https://github.com/rainlab/pages-plugin/issues/384 Refs 1d91c221b0b32592ec93c9f4824d108fc2a5cc5e --- modules/backend/assets/js/october.treeview.js | 97 +++++++++++++------ 1 file changed, 65 insertions(+), 32 deletions(-) diff --git a/modules/backend/assets/js/october.treeview.js b/modules/backend/assets/js/october.treeview.js index 1a22d60b9b..2783946464 100644 --- a/modules/backend/assets/js/october.treeview.js +++ b/modules/backend/assets/js/october.treeview.js @@ -4,13 +4,13 @@ * Data attributes: * - data-group-status-handler - AJAX handler to execute when an item is collapsed or expanded by a user * - data-reorder-handler - AJAX handler to execute when items are reordered - * + * * Events * - open.oc.treeview - this event is triggered on the list element when an item is clicked. - * + * * Dependences: * - Tree list (october.treelist.js) - * + * */ +function ($) { "use strict"; var Base = $.oc.foundation.base, @@ -65,8 +65,11 @@ * Mark previously active item, if it was set */ var dataId = this.$el.data('oc.active-item') - if (dataId !== undefined) + if (dataId !== undefined) { this.markActive(dataId) + } + + this.$scrollbar.on('oc.scrollEnd', this.proxy(this.onScroll)) } TreeView.prototype.dispose = function() { @@ -83,6 +86,7 @@ } TreeView.prototype.unregisterHandlers = function() { + this.$scrollbar.on('oc.scrollEnd', this.proxy(this.onScroll)) this.$el.off('.treeview') this.$el.off('move.oc.treelist', this.proxy(this.onNodeMove)) this.$el.off('aftermove.oc.treelist', this.proxy(this.onAfterNodeMove)) @@ -163,9 +167,9 @@ TreeView.prototype.toggleGroup = function(group) { var $group = $(group); - $group.attr('data-status') == 'expanded' ? - this.collapseGroup($group) : - this.expandGroup($group) + $group.attr('data-status') == 'expanded' + ? this.collapseGroup($group) + : this.expandGroup($group) } TreeView.prototype.sendGroupStatusRequest = function($group, status) { @@ -229,7 +233,7 @@ } // It seems the method is not used anymore as we re-create the control - // instead of updating it. Remove later if nothing weird is noticed. + // instead of updating it. Remove later if nothing weird is noticed. // -ab Apr 26 2015 // TreeView.prototype.update = function() { @@ -238,8 +242,9 @@ //this.initSortable() var dataId = this.$el.data('oc.active-item') - if (dataId !== undefined) + if (dataId !== undefined) { this.markActive(dataId) + } } TreeView.prototype.handleMovedNode = function() { @@ -250,11 +255,13 @@ } TreeView.prototype.tweakCursorAdjustment = function(adjustment) { - if (!adjustment) + if (!adjustment) { return adjustment + } - if (this.$scrollbar.length > 0) + if (this.$scrollbar.length > 0) { adjustment.top -= this.$scrollbar.scrollTop() + } return adjustment } @@ -297,46 +304,71 @@ this.toggleGroup($(ev.currentTarget).closest('li')) return false } - + // TREEVIEW SCROLL ON DRAG // ============================ - + + TreeView.prototype.onScroll = function () { + if (!$('body').hasClass('dragging')) { + return + } + + var changed = this.lastScrollPos - this.$scrollbar.scrollTop() + + this.$el.children('ol').each(function() { + var sortable = $(this).data('oc.sortable') + + sortable.refresh() + sortable.cursorAdjustment.top += changed // Keep cursor adjustment in sync with scroll + }); + + this.dragCallback() + + this.lastScrollPos = this.$scrollbar.scrollTop() + } + TreeView.prototype.onDrag = function ($item, position, _super, event) { - + this.lastScrollPos = this.$scrollbar.scrollTop() + this.dragCallback = function() { _super($item, position, null, event) }; - + this.clearScrollTimeout() this.dragCallback() - + if (!this.$scrollbar || this.$scrollbar.length === 0) return - - if (position.top < 0) + + if (position.top < 0) { this.scrollOffset = -10 + Math.floor(position.top / 5) - else if (position.top > this.$scrollbar.height()) + } + else if (position.top > this.$scrollbar.height()) { this.scrollOffset = 10 + Math.ceil((position.top - this.$scrollbar.height()) / 5) - else + } + else { return - - this.scrollMax = function() { - return this.$el.height() - this.$scrollbar.height() - }; - + } + this.dragScroll() } - + + TreeView.prototype.scrollMax = function() { + return this.$el.height() - this.$scrollbar.height() + } + TreeView.prototype.dragScroll = function() { var startScrollTop = this.$scrollbar.scrollTop() var changed this.scrollTimeout = null - this.$scrollbar.scrollTop( Math.min(startScrollTop + this.scrollOffset, this.scrollMax()) ) + this.$scrollbar.scrollTop(Math.min(startScrollTop + this.scrollOffset, this.scrollMax())) + changed = this.$scrollbar.scrollTop() - startScrollTop - if (changed === 0) + if (changed === 0) { return + } this.$el.children('ol').each(function() { var sortable = $(this).data('oc.sortable') @@ -346,11 +378,12 @@ }); this.dragCallback() + this.$scrollbar.data('oc.scrollbar').setThumbPosition() // Update scrollbar position - + this.scrollTimeout = window.setTimeout(this.proxy(this.dragScroll), 100) } - + TreeView.prototype.clearScrollTimeout = function() { if (this.scrollTimeout) { window.clearTimeout(this.scrollTimeout) @@ -372,7 +405,7 @@ var options = $.extend({}, TreeView.DEFAULTS, $this.data(), typeof option == 'object' && option) if (!data) $this.data('oc.treeView', (data = new TreeView(this, options))) - if (typeof option == 'string' && data) { + if (typeof option == 'string' && data) { var methodArgs = []; for (var i=1; i Date: Fri, 13 Dec 2019 21:44:37 +1100 Subject: [PATCH 155/157] Remove GPU enablement It is unsure why this was ever needed, but it appears to fix the overflow issues with the sortable plugin Refs https://github.com/rainlab/pages-plugin/issues/384 Refs 11be3fede39024f285309f61cbf32ee4d0d5cc28 --- modules/backend/assets/css/october.css | 3 +-- modules/backend/assets/js/october.treeview.js | 2 -- modules/backend/assets/less/controls/scrollbar.less | 7 +------ 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/modules/backend/assets/css/october.css b/modules/backend/assets/css/october.css index fb572f7c55..3ee63a995a 100644 --- a/modules/backend/assets/css/october.css +++ b/modules/backend/assets/css/october.css @@ -115,8 +115,7 @@ .control-simplelist.is-selectable-box li a:hover .image >i {color:rgba(0,0,0,0.45)} .list-preview .control-simplelist.is-selectable ul {margin-bottom:0} .drag-noselect {-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none} -.control-scrollbar {position:relative;overflow:hidden;height:100%;-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0)} -.control-scrollbar >div {-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0)} +.control-scrollbar {position:relative;overflow:hidden;height:100%} .control-scrollbar >.scrollbar-scrollbar {position:absolute;z-index:100} .control-scrollbar >.scrollbar-scrollbar .scrollbar-track {background-color:transparent;position:relative;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px} .control-scrollbar >.scrollbar-scrollbar .scrollbar-track .scrollbar-thumb {background-color:rgba(0,0,0,0.35);-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;cursor:pointer;overflow:hidden;position:absolute} diff --git a/modules/backend/assets/js/october.treeview.js b/modules/backend/assets/js/october.treeview.js index 2783946464..15bf14cc74 100644 --- a/modules/backend/assets/js/october.treeview.js +++ b/modules/backend/assets/js/october.treeview.js @@ -317,7 +317,6 @@ this.$el.children('ol').each(function() { var sortable = $(this).data('oc.sortable') - sortable.refresh() sortable.cursorAdjustment.top += changed // Keep cursor adjustment in sync with scroll }); @@ -372,7 +371,6 @@ this.$el.children('ol').each(function() { var sortable = $(this).data('oc.sortable') - sortable.refresh() sortable.cursorAdjustment.top -= changed // Keep cursor adjustment in sync with scroll }); diff --git a/modules/backend/assets/less/controls/scrollbar.less b/modules/backend/assets/less/controls/scrollbar.less index 92f6bd4449..d4966e5d78 100644 --- a/modules/backend/assets/less/controls/scrollbar.less +++ b/modules/backend/assets/less/controls/scrollbar.less @@ -12,11 +12,6 @@ position: relative; overflow: hidden; height: 100%; - .transform( ~'translateZ(0)'); - - > div { - .transform( ~'translateZ(0)'); - } >.scrollbar-scrollbar { position: absolute; @@ -127,4 +122,4 @@ html.mobile { } } } -} \ No newline at end of file +} From cc191663763562a4732d6e51eabebc0559e2f788 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Fri, 13 Dec 2019 21:56:39 +1100 Subject: [PATCH 156/157] Event goes off not on --- modules/backend/assets/js/october.treeview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/backend/assets/js/october.treeview.js b/modules/backend/assets/js/october.treeview.js index 15bf14cc74..f443429c1d 100644 --- a/modules/backend/assets/js/october.treeview.js +++ b/modules/backend/assets/js/october.treeview.js @@ -86,7 +86,7 @@ } TreeView.prototype.unregisterHandlers = function() { - this.$scrollbar.on('oc.scrollEnd', this.proxy(this.onScroll)) + this.$scrollbar.off('oc.scrollEnd', this.proxy(this.onScroll)) this.$el.off('.treeview') this.$el.off('move.oc.treelist', this.proxy(this.onNodeMove)) this.$el.off('aftermove.oc.treelist', this.proxy(this.onAfterNodeMove)) From c9189c31b3d879a610c38ef39b3a1b38fe8cdd1c Mon Sep 17 00:00:00 2001 From: Ayumi Hamasaki Date: Sun, 7 Jun 2020 22:17:33 +0100 Subject: [PATCH 157/157] jquery 3.5.1 --- .../js/vendor/jquery-and-migrate.min.js | 220 +----------------- .../assets/js/vendor/jquery-migrate.min.js | 217 +---------------- 2 files changed, 6 insertions(+), 431 deletions(-) diff --git a/modules/backend/assets/js/vendor/jquery-and-migrate.min.js b/modules/backend/assets/js/vendor/jquery-and-migrate.min.js index 8598024257..e70fa49b51 100644 --- a/modules/backend/assets/js/vendor/jquery-and-migrate.min.js +++ b/modules/backend/assets/js/vendor/jquery-and-migrate.min.js @@ -1,217 +1,5 @@ -/*! jQuery v3.3.1 | (c) JS Foundation and other contributors | jquery.org/license */ -!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(e,t){"use strict";var n=[],r=e.document,i=Object.getPrototypeOf,o=n.slice,a=n.concat,s=n.push,u=n.indexOf,l={},c=l.toString,f=l.hasOwnProperty,p=f.toString,d=p.call(Object),h={},g=function e(t){return"function"==typeof t&&"number"!=typeof t.nodeType},y=function e(t){return null!=t&&t===t.window},v={type:!0,src:!0,noModule:!0};function m(e,t,n){var i,o=(t=t||r).createElement("script");if(o.text=e,n)for(i in v)n[i]&&(o[i]=n[i]);t.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[c.call(e)]||"object":typeof e}var b="3.3.1",w=function(e,t){return new w.fn.init(e,t)},T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;w.fn=w.prototype={jquery:"3.3.1",constructor:w,length:0,toArray:function(){return o.call(this)},get:function(e){return null==e?o.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=w.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return w.each(this,e)},map:function(e){return this.pushStack(w.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(o.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n0&&t-1 in e)}var E=function(e){var t,n,r,i,o,a,s,u,l,c,f,p,d,h,g,y,v,m,x,b="sizzle"+1*new Date,w=e.document,T=0,C=0,E=ae(),k=ae(),S=ae(),D=function(e,t){return e===t&&(f=!0),0},N={}.hasOwnProperty,A=[],j=A.pop,q=A.push,L=A.push,H=A.slice,O=function(e,t){for(var n=0,r=e.length;n+~]|"+M+")"+M+"*"),z=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),X=new RegExp(W),U=new RegExp("^"+R+"$"),V={ID:new RegExp("^#("+R+")"),CLASS:new RegExp("^\\.("+R+")"),TAG:new RegExp("^("+R+"|[*])"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+P+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},G=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Q=/^[^{]+\{\s*\[native \w/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,K=/[+~]/,Z=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ee=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},te=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ne=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},re=function(){p()},ie=me(function(e){return!0===e.disabled&&("form"in e||"label"in e)},{dir:"parentNode",next:"legend"});try{L.apply(A=H.call(w.childNodes),w.childNodes),A[w.childNodes.length].nodeType}catch(e){L={apply:A.length?function(e,t){q.apply(e,H.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function oe(e,t,r,i){var o,s,l,c,f,h,v,m=t&&t.ownerDocument,T=t?t.nodeType:9;if(r=r||[],"string"!=typeof e||!e||1!==T&&9!==T&&11!==T)return r;if(!i&&((t?t.ownerDocument||t:w)!==d&&p(t),t=t||d,g)){if(11!==T&&(f=J.exec(e)))if(o=f[1]){if(9===T){if(!(l=t.getElementById(o)))return r;if(l.id===o)return r.push(l),r}else if(m&&(l=m.getElementById(o))&&x(t,l)&&l.id===o)return r.push(l),r}else{if(f[2])return L.apply(r,t.getElementsByTagName(e)),r;if((o=f[3])&&n.getElementsByClassName&&t.getElementsByClassName)return L.apply(r,t.getElementsByClassName(o)),r}if(n.qsa&&!S[e+" "]&&(!y||!y.test(e))){if(1!==T)m=t,v=e;else if("object"!==t.nodeName.toLowerCase()){(c=t.getAttribute("id"))?c=c.replace(te,ne):t.setAttribute("id",c=b),s=(h=a(e)).length;while(s--)h[s]="#"+c+" "+ve(h[s]);v=h.join(","),m=K.test(e)&&ge(t.parentNode)||t}if(v)try{return L.apply(r,m.querySelectorAll(v)),r}catch(e){}finally{c===b&&t.removeAttribute("id")}}}return u(e.replace(B,"$1"),t,r,i)}function ae(){var e=[];function t(n,i){return e.push(n+" ")>r.cacheLength&&delete t[e.shift()],t[n+" "]=i}return t}function se(e){return e[b]=!0,e}function ue(e){var t=d.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function le(e,t){var n=e.split("|"),i=n.length;while(i--)r.attrHandle[n[i]]=t}function ce(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function fe(e){return function(t){return"input"===t.nodeName.toLowerCase()&&t.type===e}}function pe(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function de(e){return function(t){return"form"in t?t.parentNode&&!1===t.disabled?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&ie(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function he(e){return se(function(t){return t=+t,se(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function ge(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}n=oe.support={},o=oe.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},p=oe.setDocument=function(e){var t,i,a=e?e.ownerDocument||e:w;return a!==d&&9===a.nodeType&&a.documentElement?(d=a,h=d.documentElement,g=!o(d),w!==d&&(i=d.defaultView)&&i.top!==i&&(i.addEventListener?i.addEventListener("unload",re,!1):i.attachEvent&&i.attachEvent("onunload",re)),n.attributes=ue(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ue(function(e){return e.appendChild(d.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=Q.test(d.getElementsByClassName),n.getById=ue(function(e){return h.appendChild(e).id=b,!d.getElementsByName||!d.getElementsByName(b).length}),n.getById?(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){return e.getAttribute("id")===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n=t.getElementById(e);return n?[n]:[]}}):(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),r.find.TAG=n.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):n.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},r.find.CLASS=n.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&g)return t.getElementsByClassName(e)},v=[],y=[],(n.qsa=Q.test(d.querySelectorAll))&&(ue(function(e){h.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+P+")"),e.querySelectorAll("[id~="+b+"-]").length||y.push("~="),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+b+"+*").length||y.push(".#.+[+~]")}),ue(function(e){e.innerHTML="";var t=d.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),h.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.push(",.*:")})),(n.matchesSelector=Q.test(m=h.matches||h.webkitMatchesSelector||h.mozMatchesSelector||h.oMatchesSelector||h.msMatchesSelector))&&ue(function(e){n.disconnectedMatch=m.call(e,"*"),m.call(e,"[s!='']:x"),v.push("!=",W)}),y=y.length&&new RegExp(y.join("|")),v=v.length&&new RegExp(v.join("|")),t=Q.test(h.compareDocumentPosition),x=t||Q.test(h.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return f=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(1&(r=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!n.sortDetached&&t.compareDocumentPosition(e)===r?e===d||e.ownerDocument===w&&x(w,e)?-1:t===d||t.ownerDocument===w&&x(w,t)?1:c?O(c,e)-O(c,t):0:4&r?-1:1)}:function(e,t){if(e===t)return f=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===d?-1:t===d?1:i?-1:o?1:c?O(c,e)-O(c,t):0;if(i===o)return ce(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?ce(a[r],s[r]):a[r]===w?-1:s[r]===w?1:0},d):d},oe.matches=function(e,t){return oe(e,null,null,t)},oe.matchesSelector=function(e,t){if((e.ownerDocument||e)!==d&&p(e),t=t.replace(z,"='$1']"),n.matchesSelector&&g&&!S[t+" "]&&(!v||!v.test(t))&&(!y||!y.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){}return oe(t,d,null,[e]).length>0},oe.contains=function(e,t){return(e.ownerDocument||e)!==d&&p(e),x(e,t)},oe.attr=function(e,t){(e.ownerDocument||e)!==d&&p(e);var i=r.attrHandle[t.toLowerCase()],o=i&&N.call(r.attrHandle,t.toLowerCase())?i(e,t,!g):void 0;return void 0!==o?o:n.attributes||!g?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null},oe.escape=function(e){return(e+"").replace(te,ne)},oe.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},oe.uniqueSort=function(e){var t,r=[],i=0,o=0;if(f=!n.detectDuplicates,c=!n.sortStable&&e.slice(0),e.sort(D),f){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return c=null,e},i=oe.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else while(t=e[r++])n+=i(t);return n},(r=oe.selectors={cacheLength:50,createPseudo:se,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(Z,ee),e[3]=(e[3]||e[4]||e[5]||"").replace(Z,ee),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||oe.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&oe.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return V.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=a(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(Z,ee).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=E[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&E(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=oe.attr(r,e);return null==i?"!="===t:!t||(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i.replace($," ")+" ").indexOf(n)>-1:"|="===t&&(i===n||i.slice(0,n.length+1)===n+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,d,h,g=o!==a?"nextSibling":"previousSibling",y=t.parentNode,v=s&&t.nodeName.toLowerCase(),m=!u&&!s,x=!1;if(y){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===v:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?y.firstChild:y.lastChild],a&&m){x=(d=(l=(c=(f=(p=y)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1])&&l[2],p=d&&y.childNodes[d];while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if(1===p.nodeType&&++x&&p===t){c[e]=[T,d,x];break}}else if(m&&(x=d=(l=(c=(f=(p=t)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1]),!1===x)while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===v:1===p.nodeType)&&++x&&(m&&((c=(f=p[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]=[T,x]),p===t))break;return(x-=i)===r||x%r==0&&x/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||oe.error("unsupported pseudo: "+e);return i[b]?i(t):i.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?se(function(e,n){var r,o=i(e,t),a=o.length;while(a--)e[r=O(e,o[a])]=!(n[r]=o[a])}):function(e){return i(e,0,n)}):i}},pseudos:{not:se(function(e){var t=[],n=[],r=s(e.replace(B,"$1"));return r[b]?se(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),t[0]=null,!n.pop()}}),has:se(function(e){return function(t){return oe(e,t).length>0}}),contains:se(function(e){return e=e.replace(Z,ee),function(t){return(t.textContent||t.innerText||i(t)).indexOf(e)>-1}}),lang:se(function(e){return U.test(e||"")||oe.error("unsupported lang: "+e),e=e.replace(Z,ee).toLowerCase(),function(t){var n;do{if(n=g?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===h},focus:function(e){return e===d.activeElement&&(!d.hasFocus||d.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:de(!1),disabled:de(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return Y.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:he(function(){return[0]}),last:he(function(e,t){return[t-1]}),eq:he(function(e,t,n){return[n<0?n+t:n]}),even:he(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:he(function(e,t,n){for(var r=n<0?n+t:n;++r1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function be(e,t,n){for(var r=0,i=t.length;r-1&&(o[l]=!(a[l]=f))}}else v=we(v===a?v.splice(h,v.length):v),i?i(null,a,v,u):L.apply(a,v)})}function Ce(e){for(var t,n,i,o=e.length,a=r.relative[e[0].type],s=a||r.relative[" "],u=a?1:0,c=me(function(e){return e===t},s,!0),f=me(function(e){return O(t,e)>-1},s,!0),p=[function(e,n,r){var i=!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):f(e,n,r));return t=null,i}];u1&&xe(p),u>1&&ve(e.slice(0,u-1).concat({value:" "===e[u-2].type?"*":""})).replace(B,"$1"),n,u0,i=e.length>0,o=function(o,a,s,u,c){var f,h,y,v=0,m="0",x=o&&[],b=[],w=l,C=o||i&&r.find.TAG("*",c),E=T+=null==w?1:Math.random()||.1,k=C.length;for(c&&(l=a===d||a||c);m!==k&&null!=(f=C[m]);m++){if(i&&f){h=0,a||f.ownerDocument===d||(p(f),s=!g);while(y=e[h++])if(y(f,a||d,s)){u.push(f);break}c&&(T=E)}n&&((f=!y&&f)&&v--,o&&x.push(f))}if(v+=m,n&&m!==v){h=0;while(y=t[h++])y(x,b,a,s);if(o){if(v>0)while(m--)x[m]||b[m]||(b[m]=j.call(u));b=we(b)}L.apply(u,b),c&&!o&&b.length>0&&v+t.length>1&&oe.uniqueSort(u)}return c&&(T=E,l=w),x};return n?se(o):o}return s=oe.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=a(e)),n=t.length;while(n--)(o=Ce(t[n]))[b]?r.push(o):i.push(o);(o=S(e,Ee(i,r))).selector=e}return o},u=oe.select=function(e,t,n,i){var o,u,l,c,f,p="function"==typeof e&&e,d=!i&&a(e=p.selector||e);if(n=n||[],1===d.length){if((u=d[0]=d[0].slice(0)).length>2&&"ID"===(l=u[0]).type&&9===t.nodeType&&g&&r.relative[u[1].type]){if(!(t=(r.find.ID(l.matches[0].replace(Z,ee),t)||[])[0]))return n;p&&(t=t.parentNode),e=e.slice(u.shift().value.length)}o=V.needsContext.test(e)?0:u.length;while(o--){if(l=u[o],r.relative[c=l.type])break;if((f=r.find[c])&&(i=f(l.matches[0].replace(Z,ee),K.test(u[0].type)&&ge(t.parentNode)||t))){if(u.splice(o,1),!(e=i.length&&ve(u)))return L.apply(n,i),n;break}}}return(p||s(e,d))(i,t,!g,n,!t||K.test(e)&&ge(t.parentNode)||t),n},n.sortStable=b.split("").sort(D).join("")===b,n.detectDuplicates=!!f,p(),n.sortDetached=ue(function(e){return 1&e.compareDocumentPosition(d.createElement("fieldset"))}),ue(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||le("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ue(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||le("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ue(function(e){return null==e.getAttribute("disabled")})||le(P,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),oe}(e);w.find=E,w.expr=E.selectors,w.expr[":"]=w.expr.pseudos,w.uniqueSort=w.unique=E.uniqueSort,w.text=E.getText,w.isXMLDoc=E.isXML,w.contains=E.contains,w.escapeSelector=E.escape;var k=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&w(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},D=w.expr.match.needsContext;function N(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var A=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,t,n){return g(t)?w.grep(e,function(e,r){return!!t.call(e,r,e)!==n}):t.nodeType?w.grep(e,function(e){return e===t!==n}):"string"!=typeof t?w.grep(e,function(e){return u.call(t,e)>-1!==n}):w.filter(t,e,n)}w.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?w.find.matchesSelector(r,e)?[r]:[]:w.find.matches(e,w.grep(t,function(e){return 1===e.nodeType}))},w.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(w(e).filter(function(){for(t=0;t1?w.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&D.test(e)?w(e):e||[],!1).length}});var q,L=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(w.fn.init=function(e,t,n){var i,o;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(i="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:L.exec(e))||!i[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(i[1]){if(t=t instanceof w?t[0]:t,w.merge(this,w.parseHTML(i[1],t&&t.nodeType?t.ownerDocument||t:r,!0)),A.test(i[1])&&w.isPlainObject(t))for(i in t)g(this[i])?this[i](t[i]):this.attr(i,t[i]);return this}return(o=r.getElementById(i[2]))&&(this[0]=o,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):g(e)?void 0!==n.ready?n.ready(e):e(w):w.makeArray(e,this)}).prototype=w.fn,q=w(r);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};w.fn.extend({has:function(e){var t=w(e,this),n=t.length;return this.filter(function(){for(var e=0;e-1:1===n.nodeType&&w.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?w.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?u.call(w(e),this[0]):u.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(w.uniqueSort(w.merge(this.get(),w(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}w.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return k(e,"parentNode")},parentsUntil:function(e,t,n){return k(e,"parentNode",n)},next:function(e){return P(e,"nextSibling")},prev:function(e){return P(e,"previousSibling")},nextAll:function(e){return k(e,"nextSibling")},prevAll:function(e){return k(e,"previousSibling")},nextUntil:function(e,t,n){return k(e,"nextSibling",n)},prevUntil:function(e,t,n){return k(e,"previousSibling",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return N(e,"iframe")?e.contentDocument:(N(e,"template")&&(e=e.content||e),w.merge([],e.childNodes))}},function(e,t){w.fn[e]=function(n,r){var i=w.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=w.filter(r,i)),this.length>1&&(O[e]||w.uniqueSort(i),H.test(e)&&i.reverse()),this.pushStack(i)}});var M=/[^\x20\t\r\n\f]+/g;function R(e){var t={};return w.each(e.match(M)||[],function(e,n){t[n]=!0}),t}w.Callbacks=function(e){e="string"==typeof e?R(e):w.extend({},e);var t,n,r,i,o=[],a=[],s=-1,u=function(){for(i=i||e.once,r=t=!0;a.length;s=-1){n=a.shift();while(++s-1)o.splice(n,1),n<=s&&s--}),this},has:function(e){return e?w.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return i=a=[],o=n="",this},disabled:function(){return!o},lock:function(){return i=a=[],n||t||(o=n=""),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=[e,(n=n||[]).slice?n.slice():n],a.push(n),t||u()),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!r}};return l};function I(e){return e}function W(e){throw e}function $(e,t,n,r){var i;try{e&&g(i=e.promise)?i.call(e).done(t).fail(n):e&&g(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}w.extend({Deferred:function(t){var n=[["notify","progress",w.Callbacks("memory"),w.Callbacks("memory"),2],["resolve","done",w.Callbacks("once memory"),w.Callbacks("once memory"),0,"resolved"],["reject","fail",w.Callbacks("once memory"),w.Callbacks("once memory"),1,"rejected"]],r="pending",i={state:function(){return r},always:function(){return o.done(arguments).fail(arguments),this},"catch":function(e){return i.then(null,e)},pipe:function(){var e=arguments;return w.Deferred(function(t){w.each(n,function(n,r){var i=g(e[r[4]])&&e[r[4]];o[r[1]](function(){var e=i&&i.apply(this,arguments);e&&g(e.promise)?e.promise().progress(t.notify).done(t.resolve).fail(t.reject):t[r[0]+"With"](this,i?[e]:arguments)})}),e=null}).promise()},then:function(t,r,i){var o=0;function a(t,n,r,i){return function(){var s=this,u=arguments,l=function(){var e,l;if(!(t=o&&(r!==W&&(s=void 0,u=[e]),n.rejectWith(s,u))}};t?c():(w.Deferred.getStackHook&&(c.stackTrace=w.Deferred.getStackHook()),e.setTimeout(c))}}return w.Deferred(function(e){n[0][3].add(a(0,e,g(i)?i:I,e.notifyWith)),n[1][3].add(a(0,e,g(t)?t:I)),n[2][3].add(a(0,e,g(r)?r:W))}).promise()},promise:function(e){return null!=e?w.extend(e,i):i}},o={};return w.each(n,function(e,t){var a=t[2],s=t[5];i[t[1]]=a.add,s&&a.add(function(){r=s},n[3-e][2].disable,n[3-e][3].disable,n[0][2].lock,n[0][3].lock),a.add(t[3].fire),o[t[0]]=function(){return o[t[0]+"With"](this===o?void 0:this,arguments),this},o[t[0]+"With"]=a.fireWith}),i.promise(o),t&&t.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),i=o.call(arguments),a=w.Deferred(),s=function(e){return function(n){r[e]=this,i[e]=arguments.length>1?o.call(arguments):n,--t||a.resolveWith(r,i)}};if(t<=1&&($(e,a.done(s(n)).resolve,a.reject,!t),"pending"===a.state()||g(i[n]&&i[n].then)))return a.then();while(n--)$(i[n],s(n),a.reject);return a.promise()}});var B=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;w.Deferred.exceptionHook=function(t,n){e.console&&e.console.warn&&t&&B.test(t.name)&&e.console.warn("jQuery.Deferred exception: "+t.message,t.stack,n)},w.readyException=function(t){e.setTimeout(function(){throw t})};var F=w.Deferred();w.fn.ready=function(e){return F.then(e)["catch"](function(e){w.readyException(e)}),this},w.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--w.readyWait:w.isReady)||(w.isReady=!0,!0!==e&&--w.readyWait>0||F.resolveWith(r,[w]))}}),w.ready.then=F.then;function _(){r.removeEventListener("DOMContentLoaded",_),e.removeEventListener("load",_),w.ready()}"complete"===r.readyState||"loading"!==r.readyState&&!r.documentElement.doScroll?e.setTimeout(w.ready):(r.addEventListener("DOMContentLoaded",_),e.addEventListener("load",_));var z=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===x(n)){i=!0;for(s in n)z(e,t,s,n[s],!0,o,a)}else if(void 0!==r&&(i=!0,g(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(w(e),n)})),t))for(;s1,null,!0)},removeData:function(e){return this.each(function(){K.remove(this,e)})}}),w.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=J.get(e,t),n&&(!r||Array.isArray(n)?r=J.access(e,t,w.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=w.queue(e,t),r=n.length,i=n.shift(),o=w._queueHooks(e,t),a=function(){w.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return J.get(e,n)||J.access(e,n,{empty:w.Callbacks("once memory").add(function(){J.remove(e,[t+"queue",n])})})}}),w.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length\x20\t\r\n\f]+)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;function ye(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&N(e,t)?w.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n-1)i&&i.push(o);else if(l=w.contains(o.ownerDocument,o),a=ye(f.appendChild(o),"script"),l&&ve(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}!function(){var e=r.createDocumentFragment().appendChild(r.createElement("div")),t=r.createElement("input");t.setAttribute("type","radio"),t.setAttribute("checked","checked"),t.setAttribute("name","t"),e.appendChild(t),h.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,e.innerHTML="",h.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue}();var be=r.documentElement,we=/^key/,Te=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ce=/^([^.]*)(?:\.(.+)|)/;function Ee(){return!0}function ke(){return!1}function Se(){try{return r.activeElement}catch(e){}}function De(e,t,n,r,i,o){var a,s;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(s in t)De(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=ke;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return w().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=w.guid++)),e.each(function(){w.event.add(this,t,i,r,n)})}w.event={global:{},add:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.get(e);if(y){n.handler&&(n=(o=n).handler,i=o.selector),i&&w.find.matchesSelector(be,i),n.guid||(n.guid=w.guid++),(u=y.events)||(u=y.events={}),(a=y.handle)||(a=y.handle=function(t){return"undefined"!=typeof w&&w.event.triggered!==t.type?w.event.dispatch.apply(e,arguments):void 0}),l=(t=(t||"").match(M)||[""]).length;while(l--)d=g=(s=Ce.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=w.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=w.event.special[d]||{},c=w.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&w.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,a)||e.addEventListener&&e.addEventListener(d,a)),f.add&&(f.add.call(e,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),w.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.hasData(e)&&J.get(e);if(y&&(u=y.events)){l=(t=(t||"").match(M)||[""]).length;while(l--)if(s=Ce.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){f=w.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,y.handle)||w.removeEvent(e,d,y.handle),delete u[d])}else for(d in u)w.event.remove(e,d+t[l],n,r,!0);w.isEmptyObject(u)&&J.remove(e,"handle events")}},dispatch:function(e){var t=w.event.fix(e),n,r,i,o,a,s,u=new Array(arguments.length),l=(J.get(this,"events")||{})[t.type]||[],c=w.event.special[t.type]||{};for(u[0]=t,n=1;n=1))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n-1:w.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u\x20\t\r\n\f]*)[^>]*)\/>/gi,Ae=/\s*$/g;function Le(e,t){return N(e,"table")&&N(11!==t.nodeType?t:t.firstChild,"tr")?w(e).children("tbody")[0]||e:e}function He(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Oe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Pe(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(J.hasData(e)&&(o=J.access(e),a=J.set(t,o),l=o.events)){delete a.handle,a.events={};for(i in l)for(n=0,r=l[i].length;n1&&"string"==typeof y&&!h.checkClone&&je.test(y))return e.each(function(i){var o=e.eq(i);v&&(t[0]=y.call(this,i,o.html())),Re(o,t,n,r)});if(p&&(i=xe(t,e[0].ownerDocument,!1,e,r),o=i.firstChild,1===i.childNodes.length&&(i=o),o||r)){for(u=(s=w.map(ye(i,"script"),He)).length;f")},clone:function(e,t,n){var r,i,o,a,s=e.cloneNode(!0),u=w.contains(e.ownerDocument,e);if(!(h.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||w.isXMLDoc(e)))for(a=ye(s),r=0,i=(o=ye(e)).length;r0&&ve(a,!u&&ye(e,"script")),s},cleanData:function(e){for(var t,n,r,i=w.event.special,o=0;void 0!==(n=e[o]);o++)if(Y(n)){if(t=n[J.expando]){if(t.events)for(r in t.events)i[r]?w.event.remove(n,r):w.removeEvent(n,r,t.handle);n[J.expando]=void 0}n[K.expando]&&(n[K.expando]=void 0)}}}),w.fn.extend({detach:function(e){return Ie(this,e,!0)},remove:function(e){return Ie(this,e)},text:function(e){return z(this,function(e){return void 0===e?w.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Re(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Le(this,e).appendChild(e)})},prepend:function(){return Re(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Le(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(w.cleanData(ye(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return w.clone(this,e,t)})},html:function(e){return z(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Ae.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=w.htmlPrefilter(e);try{for(;n=0&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))),u}function et(e,t,n){var r=$e(e),i=Fe(e,t,r),o="border-box"===w.css(e,"boxSizing",!1,r),a=o;if(We.test(i)){if(!n)return i;i="auto"}return a=a&&(h.boxSizingReliable()||i===e.style[t]),("auto"===i||!parseFloat(i)&&"inline"===w.css(e,"display",!1,r))&&(i=e["offset"+t[0].toUpperCase()+t.slice(1)],a=!0),(i=parseFloat(i)||0)+Ze(e,t,n||(o?"border":"content"),a,r,i)+"px"}w.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Fe(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=G(t),u=Xe.test(t),l=e.style;if(u||(t=Je(s)),a=w.cssHooks[t]||w.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"==(o=typeof n)&&(i=ie.exec(n))&&i[1]&&(n=ue(e,t,i),o="number"),null!=n&&n===n&&("number"===o&&(n+=i&&i[3]||(w.cssNumber[s]?"":"px")),h.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=G(t);return Xe.test(t)||(t=Je(s)),(a=w.cssHooks[t]||w.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Fe(e,t,r)),"normal"===i&&t in Ve&&(i=Ve[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),w.each(["height","width"],function(e,t){w.cssHooks[t]={get:function(e,n,r){if(n)return!ze.test(w.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?et(e,t,r):se(e,Ue,function(){return et(e,t,r)})},set:function(e,n,r){var i,o=$e(e),a="border-box"===w.css(e,"boxSizing",!1,o),s=r&&Ze(e,t,r,a,o);return a&&h.scrollboxSize()===o.position&&(s-=Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-parseFloat(o[t])-Ze(e,t,"border",!1,o)-.5)),s&&(i=ie.exec(n))&&"px"!==(i[3]||"px")&&(e.style[t]=n,n=w.css(e,t)),Ke(e,n,s)}}}),w.cssHooks.marginLeft=_e(h.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Fe(e,"marginLeft"))||e.getBoundingClientRect().left-se(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),w.each({margin:"",padding:"",border:"Width"},function(e,t){w.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+oe[r]+t]=o[r]||o[r-2]||o[0];return i}},"margin"!==e&&(w.cssHooks[e+t].set=Ke)}),w.fn.extend({css:function(e,t){return z(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=$e(e),i=t.length;a1)}});function tt(e,t,n,r,i){return new tt.prototype.init(e,t,n,r,i)}w.Tween=tt,tt.prototype={constructor:tt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||w.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(w.cssNumber[n]?"":"px")},cur:function(){var e=tt.propHooks[this.prop];return e&&e.get?e.get(this):tt.propHooks._default.get(this)},run:function(e){var t,n=tt.propHooks[this.prop];return this.options.duration?this.pos=t=w.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):tt.propHooks._default.set(this),this}},tt.prototype.init.prototype=tt.prototype,tt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=w.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){w.fx.step[e.prop]?w.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[w.cssProps[e.prop]]&&!w.cssHooks[e.prop]?e.elem[e.prop]=e.now:w.style(e.elem,e.prop,e.now+e.unit)}}},tt.propHooks.scrollTop=tt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},w.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},w.fx=tt.prototype.init,w.fx.step={};var nt,rt,it=/^(?:toggle|show|hide)$/,ot=/queueHooks$/;function at(){rt&&(!1===r.hidden&&e.requestAnimationFrame?e.requestAnimationFrame(at):e.setTimeout(at,w.fx.interval),w.fx.tick())}function st(){return e.setTimeout(function(){nt=void 0}),nt=Date.now()}function ut(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=oe[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function lt(e,t,n){for(var r,i=(pt.tweeners[t]||[]).concat(pt.tweeners["*"]),o=0,a=i.length;o1)},removeAttr:function(e){return this.each(function(){w.removeAttr(this,e)})}}),w.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?w.prop(e,t,n):(1===o&&w.isXMLDoc(e)||(i=w.attrHooks[t.toLowerCase()]||(w.expr.match.bool.test(t)?dt:void 0)),void 0!==n?null===n?void w.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=w.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!h.radioValue&&"radio"===t&&N(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(M);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),dt={set:function(e,t,n){return!1===t?w.removeAttr(e,n):e.setAttribute(n,n),n}},w.each(w.expr.match.bool.source.match(/\w+/g),function(e,t){var n=ht[t]||w.find.attr;ht[t]=function(e,t,r){var i,o,a=t.toLowerCase();return r||(o=ht[a],ht[a]=i,i=null!=n(e,t,r)?a:null,ht[a]=o),i}});var gt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;w.fn.extend({prop:function(e,t){return z(this,w.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[w.propFix[e]||e]})}}),w.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&w.isXMLDoc(e)||(t=w.propFix[t]||t,i=w.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=w.find.attr(e,"tabindex");return t?parseInt(t,10):gt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),h.optSelected||(w.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),w.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){w.propFix[this.toLowerCase()]=this});function vt(e){return(e.match(M)||[]).join(" ")}function mt(e){return e.getAttribute&&e.getAttribute("class")||""}function xt(e){return Array.isArray(e)?e:"string"==typeof e?e.match(M)||[]:[]}w.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).addClass(e.call(this,t,mt(this)))});if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).removeClass(e.call(this,t,mt(this)))});if(!arguments.length)return this.attr("class","");if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])while(r.indexOf(" "+o+" ")>-1)r=r.replace(" "+o+" "," ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(e,t){var n=typeof e,r="string"===n||Array.isArray(e);return"boolean"==typeof t&&r?t?this.addClass(e):this.removeClass(e):g(e)?this.each(function(n){w(this).toggleClass(e.call(this,n,mt(this),t),t)}):this.each(function(){var t,i,o,a;if(r){i=0,o=w(this),a=xt(e);while(t=a[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else void 0!==e&&"boolean"!==n||((t=mt(this))&&J.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||!1===e?"":J.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&(" "+vt(mt(n))+" ").indexOf(t)>-1)return!0;return!1}});var bt=/\r/g;w.fn.extend({val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=g(e),this.each(function(n){var i;1===this.nodeType&&(null==(i=r?e.call(this,n,w(this).val()):e)?i="":"number"==typeof i?i+="":Array.isArray(i)&&(i=w.map(i,function(e){return null==e?"":e+""})),(t=w.valHooks[this.type]||w.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))});if(i)return(t=w.valHooks[i.type]||w.valHooks[i.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:"string"==typeof(n=i.value)?n.replace(bt,""):null==n?"":n}}}),w.extend({valHooks:{option:{get:function(e){var t=w.find.attr(e,"value");return null!=t?t:vt(w.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),w.each(["radio","checkbox"],function(){w.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=w.inArray(w(e).val(),t)>-1}},h.checkOn||(w.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),h.focusin="onfocusin"in e;var wt=/^(?:focusinfocus|focusoutblur)$/,Tt=function(e){e.stopPropagation()};w.extend(w.event,{trigger:function(t,n,i,o){var a,s,u,l,c,p,d,h,v=[i||r],m=f.call(t,"type")?t.type:t,x=f.call(t,"namespace")?t.namespace.split("."):[];if(s=h=u=i=i||r,3!==i.nodeType&&8!==i.nodeType&&!wt.test(m+w.event.triggered)&&(m.indexOf(".")>-1&&(m=(x=m.split(".")).shift(),x.sort()),c=m.indexOf(":")<0&&"on"+m,t=t[w.expando]?t:new w.Event(m,"object"==typeof t&&t),t.isTrigger=o?2:3,t.namespace=x.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+x.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=i),n=null==n?[t]:w.makeArray(n,[t]),d=w.event.special[m]||{},o||!d.trigger||!1!==d.trigger.apply(i,n))){if(!o&&!d.noBubble&&!y(i)){for(l=d.delegateType||m,wt.test(l+m)||(s=s.parentNode);s;s=s.parentNode)v.push(s),u=s;u===(i.ownerDocument||r)&&v.push(u.defaultView||u.parentWindow||e)}a=0;while((s=v[a++])&&!t.isPropagationStopped())h=s,t.type=a>1?l:d.bindType||m,(p=(J.get(s,"events")||{})[t.type]&&J.get(s,"handle"))&&p.apply(s,n),(p=c&&s[c])&&p.apply&&Y(s)&&(t.result=p.apply(s,n),!1===t.result&&t.preventDefault());return t.type=m,o||t.isDefaultPrevented()||d._default&&!1!==d._default.apply(v.pop(),n)||!Y(i)||c&&g(i[m])&&!y(i)&&((u=i[c])&&(i[c]=null),w.event.triggered=m,t.isPropagationStopped()&&h.addEventListener(m,Tt),i[m](),t.isPropagationStopped()&&h.removeEventListener(m,Tt),w.event.triggered=void 0,u&&(i[c]=u)),t.result}},simulate:function(e,t,n){var r=w.extend(new w.Event,n,{type:e,isSimulated:!0});w.event.trigger(r,null,t)}}),w.fn.extend({trigger:function(e,t){return this.each(function(){w.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return w.event.trigger(e,t,n,!0)}}),h.focusin||w.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){w.event.simulate(t,e.target,w.event.fix(e))};w.event.special[t]={setup:function(){var r=this.ownerDocument||this,i=J.access(r,t);i||r.addEventListener(e,n,!0),J.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this,i=J.access(r,t)-1;i?J.access(r,t,i):(r.removeEventListener(e,n,!0),J.remove(r,t))}}});var Ct=e.location,Et=Date.now(),kt=/\?/;w.parseXML=function(t){var n;if(!t||"string"!=typeof t)return null;try{n=(new e.DOMParser).parseFromString(t,"text/xml")}catch(e){n=void 0}return n&&!n.getElementsByTagName("parsererror").length||w.error("Invalid XML: "+t),n};var St=/\[\]$/,Dt=/\r?\n/g,Nt=/^(?:submit|button|image|reset|file)$/i,At=/^(?:input|select|textarea|keygen)/i;function jt(e,t,n,r){var i;if(Array.isArray(t))w.each(t,function(t,i){n||St.test(e)?r(e,i):jt(e+"["+("object"==typeof i&&null!=i?t:"")+"]",i,n,r)});else if(n||"object"!==x(t))r(e,t);else for(i in t)jt(e+"["+i+"]",t[i],n,r)}w.param=function(e,t){var n,r=[],i=function(e,t){var n=g(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(Array.isArray(e)||e.jquery&&!w.isPlainObject(e))w.each(e,function(){i(this.name,this.value)});else for(n in e)jt(n,e[n],t,i);return r.join("&")},w.fn.extend({serialize:function(){return w.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=w.prop(this,"elements");return e?w.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!w(this).is(":disabled")&&At.test(this.nodeName)&&!Nt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=w(this).val();return null==n?null:Array.isArray(n)?w.map(n,function(e){return{name:t.name,value:e.replace(Dt,"\r\n")}}):{name:t.name,value:n.replace(Dt,"\r\n")}}).get()}});var qt=/%20/g,Lt=/#.*$/,Ht=/([?&])_=[^&]*/,Ot=/^(.*?):[ \t]*([^\r\n]*)$/gm,Pt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Mt=/^(?:GET|HEAD)$/,Rt=/^\/\//,It={},Wt={},$t="*/".concat("*"),Bt=r.createElement("a");Bt.href=Ct.href;function Ft(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(M)||[];if(g(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function _t(e,t,n,r){var i={},o=e===Wt;function a(s){var u;return i[s]=!0,w.each(e[s]||[],function(e,s){var l=s(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):void 0:(t.dataTypes.unshift(l),a(l),!1)}),u}return a(t.dataTypes[0])||!i["*"]&&a("*")}function zt(e,t){var n,r,i=w.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&w.extend(!0,e,r),e}function Xt(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}function Ut(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}w.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ct.href,type:"GET",isLocal:Pt.test(Ct.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":$t,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":w.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,w.ajaxSettings),t):zt(w.ajaxSettings,e)},ajaxPrefilter:Ft(It),ajaxTransport:Ft(Wt),ajax:function(t,n){"object"==typeof t&&(n=t,t=void 0),n=n||{};var i,o,a,s,u,l,c,f,p,d,h=w.ajaxSetup({},n),g=h.context||h,y=h.context&&(g.nodeType||g.jquery)?w(g):w.event,v=w.Deferred(),m=w.Callbacks("once memory"),x=h.statusCode||{},b={},T={},C="canceled",E={readyState:0,getResponseHeader:function(e){var t;if(c){if(!s){s={};while(t=Ot.exec(a))s[t[1].toLowerCase()]=t[2]}t=s[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return c?a:null},setRequestHeader:function(e,t){return null==c&&(e=T[e.toLowerCase()]=T[e.toLowerCase()]||e,b[e]=t),this},overrideMimeType:function(e){return null==c&&(h.mimeType=e),this},statusCode:function(e){var t;if(e)if(c)E.always(e[E.status]);else for(t in e)x[t]=[x[t],e[t]];return this},abort:function(e){var t=e||C;return i&&i.abort(t),k(0,t),this}};if(v.promise(E),h.url=((t||h.url||Ct.href)+"").replace(Rt,Ct.protocol+"//"),h.type=n.method||n.type||h.method||h.type,h.dataTypes=(h.dataType||"*").toLowerCase().match(M)||[""],null==h.crossDomain){l=r.createElement("a");try{l.href=h.url,l.href=l.href,h.crossDomain=Bt.protocol+"//"+Bt.host!=l.protocol+"//"+l.host}catch(e){h.crossDomain=!0}}if(h.data&&h.processData&&"string"!=typeof h.data&&(h.data=w.param(h.data,h.traditional)),_t(It,h,n,E),c)return E;(f=w.event&&h.global)&&0==w.active++&&w.event.trigger("ajaxStart"),h.type=h.type.toUpperCase(),h.hasContent=!Mt.test(h.type),o=h.url.replace(Lt,""),h.hasContent?h.data&&h.processData&&0===(h.contentType||"").indexOf("application/x-www-form-urlencoded")&&(h.data=h.data.replace(qt,"+")):(d=h.url.slice(o.length),h.data&&(h.processData||"string"==typeof h.data)&&(o+=(kt.test(o)?"&":"?")+h.data,delete h.data),!1===h.cache&&(o=o.replace(Ht,"$1"),d=(kt.test(o)?"&":"?")+"_="+Et+++d),h.url=o+d),h.ifModified&&(w.lastModified[o]&&E.setRequestHeader("If-Modified-Since",w.lastModified[o]),w.etag[o]&&E.setRequestHeader("If-None-Match",w.etag[o])),(h.data&&h.hasContent&&!1!==h.contentType||n.contentType)&&E.setRequestHeader("Content-Type",h.contentType),E.setRequestHeader("Accept",h.dataTypes[0]&&h.accepts[h.dataTypes[0]]?h.accepts[h.dataTypes[0]]+("*"!==h.dataTypes[0]?", "+$t+"; q=0.01":""):h.accepts["*"]);for(p in h.headers)E.setRequestHeader(p,h.headers[p]);if(h.beforeSend&&(!1===h.beforeSend.call(g,E,h)||c))return E.abort();if(C="abort",m.add(h.complete),E.done(h.success),E.fail(h.error),i=_t(Wt,h,n,E)){if(E.readyState=1,f&&y.trigger("ajaxSend",[E,h]),c)return E;h.async&&h.timeout>0&&(u=e.setTimeout(function(){E.abort("timeout")},h.timeout));try{c=!1,i.send(b,k)}catch(e){if(c)throw e;k(-1,e)}}else k(-1,"No Transport");function k(t,n,r,s){var l,p,d,b,T,C=n;c||(c=!0,u&&e.clearTimeout(u),i=void 0,a=s||"",E.readyState=t>0?4:0,l=t>=200&&t<300||304===t,r&&(b=Xt(h,E,r)),b=Ut(h,b,E,l),l?(h.ifModified&&((T=E.getResponseHeader("Last-Modified"))&&(w.lastModified[o]=T),(T=E.getResponseHeader("etag"))&&(w.etag[o]=T)),204===t||"HEAD"===h.type?C="nocontent":304===t?C="notmodified":(C=b.state,p=b.data,l=!(d=b.error))):(d=C,!t&&C||(C="error",t<0&&(t=0))),E.status=t,E.statusText=(n||C)+"",l?v.resolveWith(g,[p,C,E]):v.rejectWith(g,[E,C,d]),E.statusCode(x),x=void 0,f&&y.trigger(l?"ajaxSuccess":"ajaxError",[E,h,l?p:d]),m.fireWith(g,[E,C]),f&&(y.trigger("ajaxComplete",[E,h]),--w.active||w.event.trigger("ajaxStop")))}return E},getJSON:function(e,t,n){return w.get(e,t,n,"json")},getScript:function(e,t){return w.get(e,void 0,t,"script")}}),w.each(["get","post"],function(e,t){w[t]=function(e,n,r,i){return g(n)&&(i=i||r,r=n,n=void 0),w.ajax(w.extend({url:e,type:t,dataType:i,data:n,success:r},w.isPlainObject(e)&&e))}}),w._evalUrl=function(e){return w.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},w.fn.extend({wrapAll:function(e){var t;return this[0]&&(g(e)&&(e=e.call(this[0])),t=w(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(e){return g(e)?this.each(function(t){w(this).wrapInner(e.call(this,t))}):this.each(function(){var t=w(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=g(e);return this.each(function(n){w(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(e){return this.parent(e).not("body").each(function(){w(this).replaceWith(this.childNodes)}),this}}),w.expr.pseudos.hidden=function(e){return!w.expr.pseudos.visible(e)},w.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},w.ajaxSettings.xhr=function(){try{return new e.XMLHttpRequest}catch(e){}};var Vt={0:200,1223:204},Gt=w.ajaxSettings.xhr();h.cors=!!Gt&&"withCredentials"in Gt,h.ajax=Gt=!!Gt,w.ajaxTransport(function(t){var n,r;if(h.cors||Gt&&!t.crossDomain)return{send:function(i,o){var a,s=t.xhr();if(s.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(a in t.xhrFields)s[a]=t.xhrFields[a];t.mimeType&&s.overrideMimeType&&s.overrideMimeType(t.mimeType),t.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");for(a in i)s.setRequestHeader(a,i[a]);n=function(e){return function(){n&&(n=r=s.onload=s.onerror=s.onabort=s.ontimeout=s.onreadystatechange=null,"abort"===e?s.abort():"error"===e?"number"!=typeof s.status?o(0,"error"):o(s.status,s.statusText):o(Vt[s.status]||s.status,s.statusText,"text"!==(s.responseType||"text")||"string"!=typeof s.responseText?{binary:s.response}:{text:s.responseText},s.getAllResponseHeaders()))}},s.onload=n(),r=s.onerror=s.ontimeout=n("error"),void 0!==s.onabort?s.onabort=r:s.onreadystatechange=function(){4===s.readyState&&e.setTimeout(function(){n&&r()})},n=n("abort");try{s.send(t.hasContent&&t.data||null)}catch(e){if(n)throw e}},abort:function(){n&&n()}}}),w.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),w.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return w.globalEval(e),e}}}),w.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),w.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(i,o){t=w("