diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b9e01e16..db47cff60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ * **Build 26x** (2015-06-xx) - Introduced the October Storm client-side library. + - Introduced new *MediaFinder* form widget. - Improved the back-end administrator permissions and `RelationController` UI. - The page setting `hidden` has been renamed to `is_hidden`, this setting may need to be reapplied for some themes. - `FileUpload` form widget has been rebuilt from scratch, it now uses an interface similar to the Media Manager (see Backend > Forms docs). diff --git a/modules/cms/ServiceProvider.php b/modules/cms/ServiceProvider.php index 036a21ae0..154b98609 100644 --- a/modules/cms/ServiceProvider.php +++ b/modules/cms/ServiceProvider.php @@ -195,6 +195,10 @@ class ServiceProvider extends ModuleServiceProvider { WidgetManager::instance()->registerFormWidgets(function ($manager) { $manager->registerFormWidget('Cms\FormWidgets\Components'); + $manager->registerFormWidget('Cms\FormWidgets\MediaFinder', [ + 'label' => 'Media Finder', + 'code' => 'mediafinder' + ]); }); } diff --git a/modules/cms/formwidgets/MediaFinder.php b/modules/cms/formwidgets/MediaFinder.php new file mode 100644 index 000000000..56ea2f444 --- /dev/null +++ b/modules/cms/formwidgets/MediaFinder.php @@ -0,0 +1,83 @@ +fillFromConfig([ + 'mode', + 'prompt' + ]); + } + + /** + * {@inheritDoc} + */ + public function render() + { + $this->prepareVars(); + return $this->makePartial('mediafinder'); + } + + /** + * Prepares the list data + */ + public function prepareVars() + { + $this->vars['value'] = $this->getLoadValue(); + $this->vars['field'] = $this->formField; + $this->vars['prompt'] = str_replace('%s', '', $this->prompt); + $this->vars['mode'] = $this->mode; + } + + /** + * {@inheritDoc} + */ + public function loadAssets() + { + $this->addJs('js/mediafinder.js', 'core'); + $this->addCss('css/mediafinder.css', 'core'); + } +} \ No newline at end of file diff --git a/modules/cms/formwidgets/mediafinder/assets/css/mediafinder.css b/modules/cms/formwidgets/mediafinder/assets/css/mediafinder.css new file mode 100644 index 000000000..8898b39c4 --- /dev/null +++ b/modules/cms/formwidgets/mediafinder/assets/css/mediafinder.css @@ -0,0 +1,204 @@ +.field-mediafinder .find-object .icon-container i { + color: #95a5a6; + display: inline-block; +} +.field-mediafinder .find-object h4 { + font-weight: 600; + font-size: 13px; + color: #2b3e50; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + line-height: 150%; + margin: 15px 0 5px 0; + padding-right: 0; + -webkit-transition: padding 0.1s; + transition: padding 0.1s; + position: relative; +} +.field-mediafinder .find-object .info h4 a, +.field-mediafinder .find-object .meta a.find-remove-button { + color: #2b3e50; + display: none; + font-size: 15px; + text-decoration: none; +} +.field-mediafinder.is-populated:hover h4 a, +.field-mediafinder.is-populated:hover .meta .find-remove-button { + display: block; +} +@media (max-width: 1024px) { + .field-fileupload.is-populated .find-object h4 a, + .field-fileupload.is-populated .find-object .meta .find-remove-button { + display: block !important; + } +} +.field-mediafinder.style-image-single .find-button { + display: block; + float: left; + border: 2px dotted rgba(0, 0, 0, 0.1); + position: relative; + outline: none; +} +.field-mediafinder.style-image-single .find-button table { + position: absolute; + height: 100%; + width: 100%; +} +.field-mediafinder.style-image-single .find-button table td { + line-height: 16px; + font-size: 11px; + vertical-align: middle; + height: 100%; +} +.field-mediafinder.style-image-single .find-button table td:before { + text-align: center; + width: 100%; + display: block; + font-size: 22px; + color: rgba(0, 0, 0, 0.1); + vertical-align: middle; +} +.field-mediafinder.style-image-single .find-button table td span { + display: block; + padding: 10px; + text-align: center; +} +.field-mediafinder.style-image-single .find-button:hover { + border: 2px dotted rgba(0, 0, 0, 0.2); +} +.field-mediafinder.style-image-single .find-button:hover table td:before { + color: #5cb85c; + color: rgba(0, 0, 0, 0.2); +} +.field-mediafinder.style-image-single .find-button:focus { + border: 2px solid rgba(0, 0, 0, 0.3); + background: transparent; +} +.field-mediafinder.style-image-single .find-button:focus table td:before { + color: #5cb85c; + color: rgba(0, 0, 0, 0.2); +} +.field-mediafinder.style-image-single .find-button, +.field-mediafinder.style-image-single .find-button > table { + min-height: 100px; + min-width: 100px; +} +.field-mediafinder.style-image-single .find-object { + display: none; + padding-bottom: 66px; +} +.field-mediafinder.style-image-single .find-object .icon-container { + border: 1px solid #f6f8f9; + background: rgba(255, 255, 255, 0.5); +} +.field-mediafinder.style-image-single .find-object .icon-container img { + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + display: block; + max-width: 100%; + height: auto; +} +.field-mediafinder.style-image-single .find-object .info { + position: absolute; + left: 0; + right: 0; + bottom: 0; + height: 66px; +} +.field-mediafinder.style-image-single .find-object .meta { + position: absolute; + bottom: 65px; + left: 0; + right: 0; + margin: 0 15px; +} +.field-mediafinder.style-image-single .find-object:hover h4 { + padding-right: 20px; +} +.field-mediafinder.style-image-single.is-populated .find-button { + display: none; +} +.field-mediafinder.style-image-single.is-populated .find-object { + display: block; +} +.field-mediafinder.style-file-single { + background-color: #ffffff; + border: 1px solid #e0e0e0; + overflow: hidden; + position: relative; + padding-right: 30px; +} +.field-mediafinder.style-file-single .find-button { + position: absolute; + top: 50%; + margin-top: -44px; + height: 88px; + background: transparent; + right: -2px; + color: #595959; +} +.field-mediafinder.style-file-single .find-button i { + font-size: 14px; +} +.field-mediafinder.style-file-single .find-button:hover { + color: #333333; +} +.field-mediafinder.style-file-single .find-empty-message { + padding: 10px 0 10px 11px; + font-size: 13px; +} +.field-mediafinder.style-file-single .find-object { + display: none; + width: 100%; + padding: 8px 0 10px 0; +} +.field-mediafinder.style-file-single .find-object .icon-container { + position: absolute; + top: 0; + left: 0; + width: 15px; + padding: 0 5px; + margin: 8px 0 0 7px; + text-align: center; +} +.field-mediafinder.style-file-single .find-object .icon-container i { + line-height: 150%; + font-size: 15px; +} +.field-mediafinder.style-file-single .find-object .info { + margin-left: 34px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.field-mediafinder.style-file-single .find-object .info h4 { + display: inline; + margin: 0; + padding: 0; + font-size: 12px; + line-height: 150%; + color: #666666; +} +.field-mediafinder.style-file-single .find-object .meta { + position: absolute; + top: 50%; + margin-top: -44px; + height: 88px; + right: 34px; +} +.field-mediafinder.style-file-single .find-object .meta .find-remove-button { + position: absolute; + top: 50%; + right: 0; + height: 20px; + margin-top: -11px; + margin-right: 10px; +} +.field-mediafinder.style-file-single.is-populated .find-empty-message { + display: none; +} +.field-mediafinder.style-file-single.is-populated .find-object { + display: block; +} diff --git a/modules/cms/formwidgets/mediafinder/assets/js/mediafinder.js b/modules/cms/formwidgets/mediafinder/assets/js/mediafinder.js new file mode 100644 index 000000000..518d30dbf --- /dev/null +++ b/modules/cms/formwidgets/mediafinder/assets/js/mediafinder.js @@ -0,0 +1,144 @@ +/* + * MediaFinder plugin + * + * Data attributes: + * - data-control="mediafinder" - enables the plugin on an element + * - data-option="value" - an option with a value + * + * JavaScript API: + * $('a#someElement').recordFinder({ option: 'value' }) + * + * Dependences: + * - Some other plugin (filename.js) + */ + ++function ($) { "use strict"; + var Base = $.oc.foundation.base, + BaseProto = Base.prototype + + var MediaFinder = function (element, options) { + this.$el = $(element) + this.options = options || {} + + $.oc.foundation.controlUtils.markDisposable(element) + Base.call(this) + this.init() + } + + MediaFinder.prototype = Object.create(BaseProto) + MediaFinder.prototype.constructor = MediaFinder + + MediaFinder.prototype.init = function() { + if (this.options.isMulti === null) { + this.options.isMulti = this.$el.hasClass('is-multi') + } + + if (this.options.isImage === null) { + this.options.isImage = this.$el.hasClass('is-image') + } + + this.$el.on('click', '.find-button', this.proxy(this.onClickFindButton)) + this.$el.on('click', '.find-remove-button', this.proxy(this.onClickRemoveButton)) + this.$el.one('dispose-control', this.proxy(this.dispose)) + + this.$findValue = $('input.find-value', this.$el) + } + + MediaFinder.prototype.dispose = function() { + this.$el.off('click', '.find-button', this.proxy(this.onClickFindButton)) + this.$el.off('click', '.find-remove-button', this.proxy(this.onClickRemoveButton)) + this.$el.off('dispose-control', this.proxy(this.dispose)) + this.$el.removeData('oc.mediaFinder') + + this.$findValue = null + this.$el = null + + // In some cases options could contain callbacks, + // so it's better to clean them up too. + this.options = null + + BaseProto.dispose.call(this) + } + + MediaFinder.prototype.onClickRemoveButton = function() { + this.$findValue.val('') + this.evalIsPopulated() + } + + MediaFinder.prototype.onClickFindButton = function() { + var self = this + + new $.oc.mediaManager.popup({ + alias: 'ocmediamanager', + cropAndInsertButton: true, + onInsert: function(items) { + if (!items.length) { + alert('Please select image(s) to insert.') + return + } + + if (items.length > 1) { + alert('Please select a single item.') + return + } + + var path, publicUrl + for (var i=0, len=items.length; i table { + min-height: 100px; + min-width: 100px; + } + } + + .find-object { + display: none; + padding-bottom: 66px; + + .icon-container { + border: 1px solid #f6f8f9; + background: rgba(255,255,255,.5); + + img { + .border-radius(3px); + .img-responsive(); + } + } + + .info { + position: absolute; + left: 0; + right: 0; + bottom: 0; + height: 66px; + } + + .meta { + position: absolute; + bottom: 65px; + left: 0; + right: 0; + margin: 0 15px; + } + + &:hover { + h4 { padding-right: 20px; } + } + } + + &.is-populated { + .find-button { + display: none; + } + .find-object { + display: block; + } + } + +} \ No newline at end of file diff --git a/modules/cms/formwidgets/mediafinder/assets/less/mediafinder.less b/modules/cms/formwidgets/mediafinder/assets/less/mediafinder.less new file mode 100644 index 000000000..84012a7d1 --- /dev/null +++ b/modules/cms/formwidgets/mediafinder/assets/less/mediafinder.less @@ -0,0 +1,5 @@ +@import "../../../../../backend/assets/less/core/boot.less"; + +@import "mediafinder.base.less"; +@import "mediafinder.imagesingle.less"; +@import "mediafinder.filesingle.less"; diff --git a/modules/cms/formwidgets/mediafinder/partials/_file_single.htm b/modules/cms/formwidgets/mediafinder/partials/_file_single.htm new file mode 100644 index 000000000..2646bad88 --- /dev/null +++ b/modules/cms/formwidgets/mediafinder/partials/_file_single.htm @@ -0,0 +1,42 @@ +
+ + + + + +
+
+ +
+
+

+ +

+
+
+ + + +
+
+ + +
+ +
+ + + +
\ No newline at end of file diff --git a/modules/cms/formwidgets/mediafinder/partials/_image_single.htm b/modules/cms/formwidgets/mediafinder/partials/_image_single.htm new file mode 100644 index 000000000..abf5103a3 --- /dev/null +++ b/modules/cms/formwidgets/mediafinder/partials/_image_single.htm @@ -0,0 +1,35 @@ +
+ + + +
+
+ + +
+
+ +
+
+

+ + + + +

+
+
+ + + +
\ No newline at end of file diff --git a/modules/cms/formwidgets/mediafinder/partials/_mediafinder.htm b/modules/cms/formwidgets/mediafinder/partials/_mediafinder.htm new file mode 100644 index 000000000..48ec20ad1 --- /dev/null +++ b/modules/cms/formwidgets/mediafinder/partials/_mediafinder.htm @@ -0,0 +1,11 @@ + + makePartial('image_single') ?> + + + + makePartial('file_single') ?> + + +