diff --git a/.env.example b/.env.example index 24cb865..4616247 100644 --- a/.env.example +++ b/.env.example @@ -5,6 +5,8 @@ APP_DEBUG=true APP_URL=http://localhost APP_LOCALE=en +BAGISTO_URL=https://nurgul.com.tm/app/api/ + ACTIVE_THEME=demo BACKEND_URI=/admin CMS_ROUTE_CACHE=false diff --git a/plugins/indikator/devtools/LICENCE.md b/plugins/indikator/devtools/LICENCE.md new file mode 100644 index 0000000..38cee79 --- /dev/null +++ b/plugins/indikator/devtools/LICENCE.md @@ -0,0 +1,19 @@ +# MIT license + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/plugins/indikator/devtools/Plugin.php b/plugins/indikator/devtools/Plugin.php new file mode 100644 index 0000000..ae2275a --- /dev/null +++ b/plugins/indikator/devtools/Plugin.php @@ -0,0 +1,169 @@ + 'indikator.devtools::lang.plugin.name', + 'description' => 'indikator.devtools::lang.plugin.description', + 'author' => 'indikator.devtools::lang.plugin.author', + 'icon' => 'icon-wrench', + 'homepage' => 'https://github.com/gergo85/oc-devtools' + ]; + } + + public function registerSettings() + { + return [ + 'devtool' => [ + 'label' => 'indikator.devtools::lang.help.menu_label', + 'description' => 'indikator.devtools::lang.help.menu_description', + 'icon' => 'icon-wrench', + 'class' => 'Indikator\DevTools\Models\Settings', + 'category' => SettingsManager::CATEGORY_SYSTEM, + 'permissions' => ['indikator.devtools.settings'] + ] + ]; + } + + public function registerFormWidgets() + { + return [ + 'Indikator\DevTools\FormWidgets\Help' => [ + 'label' => 'Help', + 'code' => 'help' + ] + ]; + } + + public function registerPermissions() + { + return [ + 'indikator.devtools.editor' => [ + 'tab' => 'indikator.devtools::lang.plugin.name', + 'label' => 'indikator.devtools::lang.editor.permission', + 'order' => 100, + 'roles' => ['developer'] + ], + 'indikator.devtools.settings' => [ + 'tab' => 'indikator.devtools::lang.plugin.name', + 'label' => 'indikator.devtools::lang.help.permission', + 'order' => 200, + 'roles' => ['developer'] + ] + ]; + } + + public function boot() + { + // Add new menu + BackendMenu::registerCallback(function($manager) { + $manager->registerMenuItems('Indikator.DevTools', [ + 'editor' => [ + 'label' => 'indikator.devtools::lang.editor.menu_label', + 'url' => Backend::url('indikator/devtools/editor'), + 'icon' => 'icon-file-code-o', + 'iconSvg' => 'plugins/indikator/devtools/assets/images/devtools-icon.svg', + 'permissions' => ['indikator.devtools.editor'], + 'order' => 390, + + 'sideMenu' => [ + 'assets' => [ + 'label' => 'indikator.devtools::lang.editor.plugins', + 'icon' => 'icon-cubes', + 'url' => 'javascript:;', + 'attributes' => ['data-menu-item' => 'assets'], + 'counterLabel' => 'cms::lang.asset.unsaved_label', + 'order' => 100 + ] + ] + ] + ]); + }); + + // Add new features + Event::listen('backend.form.extendFields', function($form) + { + // Security check + if (!BackendAuth::check()) { + return; + } + + // Help docs + if ($this->tools_enabled('help') && (get_class($form->config->model) == 'Cms\Classes\Page' || get_class($form->config->model) == 'Cms\Classes\Partial' || get_class($form->config->model) == 'Cms\Classes\Layout') || get_class($form->config->model) == 'Indikator\DevTools\Classes\Asset') { + if (get_class($form->config->model) == 'Indikator\DevTools\Classes\Asset') { + $content = 'php'; + } + else { + $content = 'cms'; + } + + $form->addSecondaryTabFields([ + 'help' => [ + 'label' => '', + 'tab' => 'indikator.devtools::lang.help.tab', + 'type' => 'help', + 'content' => $content + ] + ]); + + return; + } + + // Wysiwyg editor + if ($this->tools_enabled('wysiwyg') && get_class($form->config->model) == 'Cms\Classes\Content') { + foreach ($form->getFields() as $field) { + if (!empty($field->config['type']) && $field->config['type'] == 'codeeditor') { + $field->config['type'] = $field->config['widget'] = 'richeditor'; + } + } + } + }); + } + + public function tools_enabled($name) + { + // Security check + if ($name != 'help' && $name != 'wysiwyg') { + return false; + } + + // Is enabled + if (!Tools::get($name.'_enabled', false)) { + return false; + } + + // My account + $admin = BackendAuth::getUser(); + + // Is superuser + if (Tools::get($name.'_superuser', false) && $admin->is_superuser == 1) { + return true; + } + + // Is admin group + if (Tools::get($name.'_admingroup', false) > 0 && Db::table('backend_users_groups')->where(['user_id' => $admin->id, 'user_group_id' => Tools::get($name.'_admingroup', false)])->count() == 1) { + return true; + } + + // Is current user + if (Tools::get($name.'_adminid', false) > 0 && $admin->id == Tools::get($name.'_adminid', false)) { + return true; + } + + // Finish + return false; + } +} diff --git a/plugins/indikator/devtools/README.md b/plugins/indikator/devtools/README.md new file mode 100644 index 0000000..1e84729 --- /dev/null +++ b/plugins/indikator/devtools/README.md @@ -0,0 +1,24 @@ +# Developer Tools Plugin +It is a must-have plugin for you, if you use the October's Docs a lot or you want to use the build-in wysiwyg editor on the Content page. + +## Main features +* __Edit directly plugins with the online code editor!__ +* Add a Help tab to the Pages, Partials or Layouts pages. +* Replace the code editor to wysiwyg editor on the Content page. +* Show the PHP's configuration if you logged as Superuser. +* Set a different permissions for the above features. + +## Available languages +* en - English +* hu - Magyar + +## Location of plugin +You can find it in the back-end: __Settings > System > Developer Tools__ + +## PHP's configuration +If you like to get the PHP's configuration of your server, use the following URL: www.yourwebsite.com/phpinfo + +## Installation +1. Go to the __Settings > Updates & Plugins__ page in the Backend. +1. Click on the __Install plugins__ button. +1. Type the __Developer Tools__ text in the search field. diff --git a/plugins/indikator/devtools/assets/images/devtools-icon.svg b/plugins/indikator/devtools/assets/images/devtools-icon.svg new file mode 100644 index 0000000..fe0b1cf --- /dev/null +++ b/plugins/indikator/devtools/assets/images/devtools-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/plugins/indikator/devtools/assets/october.cmspage.js b/plugins/indikator/devtools/assets/october.cmspage.js new file mode 100644 index 0000000..ba1fed0 --- /dev/null +++ b/plugins/indikator/devtools/assets/october.cmspage.js @@ -0,0 +1,706 @@ +/* + * Scripts for the CMS page. + */ ++function ($) { "use strict"; + + var Base = $.oc.foundation.base, + BaseProto = Base.prototype + + var CmsPage = function() { + + Base.call(this) + + // + // Initialization + // + + this.init() + } + + CmsPage.prototype = Object.create(BaseProto) + CmsPage.prototype.constructor = CmsPage + + CmsPage.prototype.init = function() { + $(document).ready(this.proxy(this.registerHandlers)) + } + + CmsPage.prototype.updateTemplateList = function(type) { + var $form = $('#cms-side-panel form[data-template-type='+type+']'), + templateList = type + 'List' + + $form.request(templateList + '::onUpdate', { + complete: function() { + $('button[data-control=delete-template]', $form).trigger('oc.triggerOn.update') + } + }) + } + + CmsPage.prototype.registerHandlers = function() { + var $document = $(document), + $masterTabs = $('#cms-master-tabs') + + $masterTabs.on('closed.oc.tab', this.proxy(this.onTabClosed)) + $masterTabs.on('beforeClose.oc.tab', this.proxy(this.onBeforeTabClose)) + $masterTabs.on('oc.beforeRequest', this.proxy(this.onBeforeRequest)) + $masterTabs.on('shown.bs.tab', this.proxy(this.onTabShown)) + $masterTabs.on('initTab.oc.tab', this.proxy(this.onInitTab)) + $masterTabs.on('afterAllClosed.oc.tab', this.proxy(this.onAfterAllTabsClosed)) + + $(window).on('ajaxInvalidField', this.proxy(this.ajaxInvalidField)) + $document.on('open.oc.list', '#cms-side-panel', this.proxy(this.onOpenDocument)) + $document.on('ajaxUpdate', '[data-control=filelist], [data-control=assetlist]', this.proxy(this.onAjaxUpdate)) + $document.on('ajaxError', '#cms-master-tabs form', this.proxy(this.onAjaxError)) + $document.on('ajaxSuccess', '#cms-master-tabs form', this.proxy(this.onAjaxSuccess)) + $document.on('click', '#cms-side-panel form button[data-control=create-template], #cms-side-panel form li a[data-control=create-template]', this.proxy(this.onCreateTemplateClick)) + $document.on('click', '#cms-side-panel form button[data-control=delete-template]', this.proxy(this.onDeleteTemplateClick)) + $document.on('showing.oc.inspector', '[data-inspectable]', this.proxy(this.onInspectorShowing)) + $document.on('hidden.oc.inspector', '[data-inspectable]', this.proxy(this.onInspectorHidden)) + $document.on('hiding.oc.inspector', '[data-inspectable]', this.proxy(this.onInspectorHiding)) + $document.on('click', '#cms-master-tabs > div.tab-content > .tab-pane.active .control-componentlist a.remove', this.proxy(this.onComponentRemove)) + $document.on('click', '#cms-component-list [data-component]', this.proxy(this.onComponentClick)) + } + + // EVENT HANDLERS + // ============================ + + CmsPage.prototype.onOpenDocument = function(event) { + /* + * Open a document when it's clicked in the sidebar + */ + + var $item = $(event.relatedTarget), + $form = $item.closest('[data-template-type]'), + data = { + type: $form.data('template-type'), + theme: $item.data('item-theme'), + path: $item.data('item-path') + }, + tabId = data.type + '-' + data.theme + '-' + data.path + + if (data.type == 'asset' && $item.data('editable') === undefined) + return true + + if ($form.length == 0) + return false + + /* + * Find if the tab is already opened + */ + if ($('#cms-master-tabs').data('oc.tab').goTo(tabId)) + return false + + /* + * Open a new tab + */ + $.oc.stripeLoadIndicator.show() + + $form.request('onOpenTemplate', { + data: data + }).done(function(data) { + $.oc.stripeLoadIndicator.hide() + var fileType = data.tabTitle.split('.').pop() + if (fileType == 'php' || fileType == 'js' || fileType == 'css' || fileType == 'html' || fileType == 'htm') fileType = 'icon-file-code-o' + else fileType = 'icon-file-text-o' + $('#cms-master-tabs').ocTab('addTab', data.tabTitle, data.tab, tabId, fileType) + }).always(function() { + $.oc.stripeLoadIndicator.hide() + }).fail(function(jqXHR, textStatus, errorThrown) { + alert(jqXHR.responseText.length ? jqXHR.responseText : jqXHR.statusText) + $.oc.stripeLoadIndicator.hide() + }) + + return false + } + + CmsPage.prototype.ajaxInvalidField = function(ev, element, name, messages, isFirst) { + /* + * Detect invalid fields, uncollapse the panel + */ + if (!isFirst) + return + + ev.preventDefault() + + var $el = $(element), + $panel = $el.closest('.form-tabless-fields.collapsed'), + $primaryPanel = $el.closest('.control-tabs.primary-tabs.collapsed') + + if ($panel.length > 0) + $panel.removeClass('collapsed') + + if ($primaryPanel.length > 0) { + $primaryPanel.removeClass('collapsed') + + var pane = $primaryPanel.closest('.tab-pane'), + $secondaryPanel = $('.control-tabs.secondary-tabs', pane) + + $secondaryPanel.removeClass('primary-collapsed') + } + + $el.focus() + } + + CmsPage.prototype.onTabClosed = function(ev) { + this.updateModifiedCounter() + + if ($('> div.tab-content > div.tab-pane', '#cms-master-tabs').length == 0) + this.setPageTitle('') + } + + CmsPage.prototype.onBeforeTabClose = function(ev) { + if ($.fn.table !== undefined) + $('[data-control=table]', ev.relatedTarget).table('dispose') + + $.oc.foundation.controlUtils.disposeControls(ev.relatedTarget.get(0)) + } + + CmsPage.prototype.onBeforeRequest = function(ev) { + var $form = $(ev.target) + + if ($('.components .layout-cell.error-component', $form).length > 0) { + if (!confirm('The form contains unknown components. Their properties will be lost on save. Do you want to save the form?')) + ev.preventDefault() + } + } + + CmsPage.prototype.onTabShown = function(ev) { + /* + * Listen for the tabs "shown" event to track the current template in the list + */ + + var $target = $(ev.target) + + if ($target.closest('[data-control=tab]').attr('id') != 'cms-master-tabs') + return + + var dataId = $target.closest('li').attr('data-tab-id'), + title = $target.attr('title'), + $sidePanel = $('#cms-side-panel') + + if (title) + this.setPageTitle(title) + + $sidePanel.find('[data-control=filelist]').fileList('markActive', dataId) + $sidePanel.find('form').trigger('oc.list.setActiveItem', [dataId]) + } + + CmsPage.prototype.onInitTab = function(ev, data) { + /* + * Listen for the tabs "initTab" event to inject extra controls to the tab + */ + + if ($(ev.target).attr('id') != 'cms-master-tabs') + return + + var $collapseIcon = $(''), + $panel = $('.form-tabless-fields', data.pane) + + $panel.append($collapseIcon); + + $collapseIcon.click(function() { + $panel.toggleClass('collapsed') + + if (typeof(localStorage) !== 'undefined') + localStorage.ocCmsTablessCollapsed = $panel.hasClass('collapsed') ? 1 : 0 + + window.setTimeout(function() { + $(window).trigger('oc.updateUi') + }, 500) + + return false + }) + + var $primaryCollapseIcon = $(''), + $primaryPanel = $('.control-tabs.primary-tabs', data.pane), + $secondaryPanel = $('.control-tabs.secondary-tabs', data.pane) + + if ($primaryPanel.length > 0) { + $secondaryPanel.append($primaryCollapseIcon); + + $primaryCollapseIcon.click(function() { + $primaryPanel.toggleClass('collapsed') + $secondaryPanel.toggleClass('primary-collapsed') + $(window).trigger('oc.updateUi') + if (typeof(localStorage) !== 'undefined') + localStorage.ocCmsPrimaryCollapsed = $primaryPanel.hasClass('collapsed') ? 1 : 0 + return false + }) + } + + if (typeof(localStorage) !== 'undefined') { + if (!$('a', data.tab).hasClass('new-template') && localStorage.ocCmsTablessCollapsed == 1) + $panel.addClass('collapsed') + + if (localStorage.ocCmsPrimaryCollapsed == 1) { + $primaryPanel.addClass('collapsed') + $secondaryPanel.addClass('primary-collapsed') + } + } + + var $componentListFormGroup = $('.control-componentlist', data.pane).closest('.form-group') + if ($primaryPanel.length > 0) + $primaryPanel.before($componentListFormGroup) + else + $secondaryPanel.parent().before($componentListFormGroup) + + $componentListFormGroup.removeClass() + $componentListFormGroup.addClass('layout-row min-size') + this.updateComponentListClass(data.pane) + this.updateFormEditorMode(data.pane, true) + + var $form = $('form', data.pane), + self = this + + $form.on('changed.oc.changeMonitor', function() { + $panel.trigger('modified.oc.tab') + self.updateModifiedCounter() + }) + + $form.on('unchanged.oc.changeMonitor', function() { + $panel.trigger('unmodified.oc.tab') + self.updateModifiedCounter() + }) + + this.addTokenExpanderToEditor(data.pane, $form) + } + + CmsPage.prototype.onAfterAllTabsClosed = function(ev) { + var $sidePanel = $('#cms-side-panel') + + $sidePanel.find('[data-control=filelist]').fileList('markActive', null) + $sidePanel.find('form').trigger('oc.list.setActiveItem', [null]) + } + + CmsPage.prototype.onAjaxUpdate = function(ev) { + var dataId = $('#cms-master-tabs .nav-tabs li.active').attr('data-tab-id'), + $sidePanel = $('#cms-side-panel') + + $sidePanel.find('[data-control=filelist]').fileList('markActive', dataId) + $sidePanel.find('form').trigger('oc.list.setActiveItem', [dataId]) + } + + CmsPage.prototype.onAjaxSuccess = function(ev, context, data) { + var element = ev.target + + if (data.templatePath !== undefined) { + $('input[name=templatePath]', element).val(data.templatePath) + $('input[name=templateMtime]', element).val(data.templateMtime) + $('[data-control=delete-button]', element).removeClass('hide') + $('[data-control=preview-button]', element).removeClass('hide') + + if (data.pageUrl !== undefined) + $('[data-control=preview-button]', element).attr('href', data.pageUrl) + } + + if (data.tabTitle !== undefined) { + $('#cms-master-tabs').ocTab('updateTitle', $(element).closest('.tab-pane'), data.tabTitle) + this.setPageTitle(data.tabTitle) + } + + var tabId = $('input[name=templateType]', element).val() + '-' + + $('input[name=theme]', element).val() + '-' + + $('input[name=templatePath]', element).val(); + + $('#cms-master-tabs').ocTab('updateIdentifier', $(element).closest('.tab-pane'), tabId) + + var templateType = $('input[name=templateType]', element).val() + if (templateType.length > 0) { + $.oc.cmsPage.updateTemplateList(templateType) + + if (templateType == 'layout') + this.updateLayouts(element) + } + + this.updateFormEditorMode($(element).closest('.tab-pane'), false) + + if (context.handler == 'onSave' && (!data['X_OCTOBER_ERROR_FIELDS'] && !data['X_OCTOBER_ERROR_MESSAGE'])) { + $(element).trigger('unchange.oc.changeMonitor') + } + } + + CmsPage.prototype.onAjaxError = function(ev, context, message, data, jqXHR) { + if (context.handler == 'onSave') { + if (jqXHR.responseText == 'mtime-mismatch') { + ev.preventDefault() + this.handleMtimeMismatch(ev.target) + } + } + } + + CmsPage.prototype.onCreateTemplateClick = function(ev) { + var $form = $(ev.target).closest('[data-template-type]'), + type = $form.data('template-type'), + tabId = type + Math.random(), + self = this + + $.oc.stripeLoadIndicator.show() + + $form.request('onCreateTemplate', { + data: {type: type} + }).done(function(data) { + $('#cms-master-tabs').ocTab('addTab', data.tabTitle, data.tab, tabId, $form.data('type-icon') + ' new-template') + $('#layout-side-panel').trigger('close.oc.sidePanel') + self.setPageTitle(data.tabTitle) + }).always(function() { + $.oc.stripeLoadIndicator.hide() + }) + } + + CmsPage.prototype.onDeleteTemplateClick = function(ev) { + var $el = $(ev.currentTarget), + $form = $el.closest('form'), + templateType = $form.data('template-type'), + self = this + + if (!confirm($el.data('confirmation'))) + return + + $.oc.stripeLoadIndicator.show() + + $form.request('onDeleteTemplates', { + data: {type: templateType} + }).done(function(data) { + var tabs = $('#cms-master-tabs').data('oc.tab'); + $.each(data.deleted, function(index, path){ + var + tabId = templateType + '-' + data.theme + '-' + path, + tab = tabs.findByIdentifier(tabId) + + $('#cms-master-tabs').ocTab('closeTab', tab, true) + }) + + if (data.error !== undefined && $.type(data.error) === 'string' && data.error.length) + $.oc.flashMsg({text: data.error, 'class': 'error'}) + }).always(function() { + self.updateTemplateList(templateType) + $.oc.stripeLoadIndicator.hide() + }) + } + + CmsPage.prototype.onInspectorShowing = function(ev, data) { + $(ev.currentTarget).closest('[data-control="toolbar"]').data('oc.dragScroll').goToElement(ev.currentTarget, data.callback) + + ev.stopPropagation() + } + + CmsPage.prototype.onInspectorHidden = function(ev) { + var element = ev.target, + values = $.parseJSON($('[data-inspector-values]', element).val()) + + $('[name="component_aliases[]"]', element).val(values['oc.alias']) + $('span.alias', element).text(values['oc.alias']) + } + + CmsPage.prototype.onInspectorHiding = function(ev, values) { + var element = ev.target, + values = $.parseJSON($('[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() + + $('div.layout-cell', $componentList).each(function() { + if ($cell.get(0) == this) + return true + + var $input = $('input[name="component_aliases[]"]', this) + + if ($input.val() == alias) { + ev.preventDefault() + alert('The component alias "'+alias+'" is already used.') + return false + } + }) + } + + CmsPage.prototype.onComponentRemove = function(ev) { + var element = ev.currentTarget + + $(element).trigger('change') + var pane = $(element).closest('.tab-pane'), + component = $(element).closest('div.layout-cell') + + /* + * Remove any {% component %} tags in the editor for this component + */ + var editor = $('[data-control=codeeditor]', pane) + if (editor.length) { + var alias = $('input[name="component_aliases[]"]', component).val(), + codeEditor = editor.codeEditor('getEditorObject') + + codeEditor.replace('', { + needle: "{% component '" + alias + "' %}" + }) + } + + component.remove() + $(window).trigger('oc.updateUi') + + this.updateComponentListClass(pane) + return false + } + + CmsPage.prototype.onComponentClick = function(ev) { + /* + * Determine if a page or layout is open in the master tabs + */ + + var $componentList = $('#cms-master-tabs > div.tab-content > .tab-pane.active .control-componentlist .layout') + if ($componentList.length == 0) { + alert('Components can be added only to pages, partials and layouts.') + return; + } + + var $component = $(ev.currentTarget).clone(), + $iconInput = $component.find('[data-component-icon]'), + $componentContainer = $('.layout-relative', $component), + $configInput = $component.find('[data-inspector-config]'), + $aliasInput = $component.find('[data-component-default-alias]'), + $valuesInput = $component.find('[data-inspector-values]'), + $nameInput = $component.find('[data-component-name]'), + $classInput = $component.find('[data-inspector-class]'), + alias = $aliasInput.val(), + originalAlias = alias, + counter = 2, + existingAliases = [] + + $('div.layout-cell input[name="component_aliases[]"]', $componentList).each(function() { + existingAliases.push($(this).val()) + }) + + while($.inArray(alias, existingAliases) !== -1) { + alias = originalAlias + counter + counter++ + } + + // Set the last alias used so dragComponents can use it + $('input[name="component_aliases[]"]', $(ev.currentTarget)).val(alias) + + $component.attr('data-component-attached', true) + $componentContainer.addClass($iconInput.val()) + $iconInput.remove() + + $componentContainer.attr({ + 'data-inspectable': '', + 'data-inspector-title': $component.find('span.name').text(), + 'data-inspector-description': $component.find('span.description').text(), + 'data-inspector-config': $configInput.val(), + 'data-inspector-class': $classInput.val() + }) + + $configInput.remove() + $('input[name="component_names[]"]', $component).val($nameInput.val()) + $nameInput.remove() + $('input[name="component_aliases[]"]', $component).val(alias) + $component.find('span.alias').text(alias) + $valuesInput.val($valuesInput.val().replace('--alias--', alias)) + $aliasInput.remove() + + $component.addClass('adding') + $componentList.append($component) + $componentList.closest('[data-control="toolbar"]').data('oc.dragScroll').goToElement($component) + $component.removeClass('adding') + $component.trigger('change') + + this.updateComponentListClass($component.closest('.tab-pane')) + + $(window).trigger('oc.updateUi') + } + + // INTERNAL METHODS + // ============================ + + CmsPage.prototype.updateComponentListClass = function(pane) { + var $componentList = $('.control-componentlist', pane), + $primaryPanel = $('.control-tabs.primary-tabs', pane), + $primaryTabContainer = $('.nav-tabs', $primaryPanel), + hasComponents = $('.layout', $componentList).children(':not(.hidden)').length > 0 + + $primaryTabContainer.toggleClass('component-area', hasComponents) + $componentList.toggleClass('has-components', hasComponents) + } + + CmsPage.prototype.updateFormEditorMode = function(pane, initialization) { + var $contentTypeElement = $('[data-toolbar-type]', pane) + if ($contentTypeElement.length == 0) + return + + if ($contentTypeElement.data('toolbar-type') != 'content') + return + + var fileName = $('input[name=fileName]', pane).val(), + parts = fileName.split('.'), + extension = 'txt', + mode = 'plain_text', + modes = { css: "css", htm: "html", html: "html", js: "javascript", less: "less", md: "markdown", sass: "sass", scss: "scss", txt: "plain_text", yaml: "yaml", php: "php" }, + editor = $('[data-control=codeeditor]', pane) + + if (parts.length >= 2) + extension = parts.pop().toLowerCase() + + if (modes[extension] !== undefined) + mode = modes[extension]; + + var setEditorMode = function() { + window.setTimeout(function() { + editor.data('oc.codeEditor').editor.getSession().setMode({path: 'ace/mode/'+mode}) + }, 200) + } + + if (initialization) + editor.on('oc.codeEditorReady', setEditorMode) + else + setEditorMode() + } + + CmsPage.prototype.updateModifiedCounter = function() { + var counters = { + page: { menu: 'pages', count: 0 }, + partial: { menu: 'partials', count: 0 }, + layout: { menu: 'layouts', count: 0 }, + content: { menu: 'content', count: 0 }, + asset: { menu: 'assets', count: 0} + } + + $('> div.tab-content > div.tab-pane[data-modified]', '#cms-master-tabs').each(function() { + var inputType = $('> form > input[name=templateType]', this).val() + counters[inputType].count++ + }) + + $.each(counters, function(type, data){ + $.oc.sideNav.setCounter('cms/' + data.menu, data.count); + }) + } + + CmsPage.prototype.addTokenExpanderToEditor = function(pane, $form) { + var group = $('[data-field-name=markup]', pane), + editor = $('[data-control=codeeditor]', group), + canExpand = false, + self = this + + if (!editor.length || editor.data('oc.tokenexpander')) + return + + var toolbar = editor.codeEditor('getToolbar') + + editor.tokenExpander() + + var breakButton = $('
  • ').prop({ 'class': 'tokenexpander-button' }).append( + $('').prop({ 'href': 'javascript:; '}).append( + $('').prop({ 'class': 'icon-code-fork' }) + ) + ) + + breakButton.hide().on('click', function() { + self.handleExpandToken(editor, $form) + return false + }) + + $('ul:first', toolbar).prepend(breakButton) + + editor + .on('show.oc.tokenexpander', function() { + canExpand = true + breakButton.show() + }) + .on('hide.oc.tokenexpander', function() { + canExpand = false + breakButton.hide() + }) + .on('dblclick', function(ev){ + if ((ev.metaKey || ev.ctrlKey) && canExpand) { + self.handleExpandToken(editor, $form) + } + }) + } + + CmsPage.prototype.handleExpandToken = function(editor, $form) { + editor.tokenExpander('expandToken', function(token, value){ + return $form.request('onExpandMarkupToken', { + data: { tokenType: token, tokenName: value } + }) + }) + } + + CmsPage.prototype.handleMtimeMismatch = function(form) { + var $form = $(form) + $form.popup({ handler: 'onOpenConcurrencyResolveForm' }) + + var popup = $form.data('oc.popup'), + self = this + + $(popup.$content).on('click', 'button[data-action=reload]', function() { + popup.hide() + self.reloadForm(form) + }) + + $(popup.$content).on('click', 'button[data-action=save]', function() { + popup.hide() + + $('input[name=templateForceSave]', $form).val(1) + $('a[data-request=onSave]', $form).trigger('click') + $('input[name=templateForceSave]', $form).val(0) + }) + } + + CmsPage.prototype.reloadForm = function(form) { + var + $form = $(form), + data = { + type: $('[name=templateType]', $form).val(), + theme: $('[name=theme]', $form).val(), + path: $('[name=templatePath]', $form).val(), + }, + tabId = data.type + '-' + data.theme + '-' + data.path, + tabs = $('#cms-master-tabs').data('oc.tab'), + tab = tabs.findByIdentifier(tabId), + self = this + + /* + * Update tab + */ + + $.oc.stripeLoadIndicator.show() + + $form.request('onOpenTemplate', { + data: data + }).done(function(data) { + $('#cms-master-tabs').ocTab('updateTab', tab, data.tabTitle, data.tab) + $('#cms-master-tabs').ocTab('unmodifyTab', tab) + self.updateModifiedCounter() + }).always(function() { + $.oc.stripeLoadIndicator.hide() + }).fail(function(jqXHR, textStatus, errorThrown) { + alert(jqXHR.responseText.length ? jqXHR.responseText : jqXHR.statusText) + }) + } + + CmsPage.prototype.setPageTitle = function(title) { + if (title.length) + $.oc.layout.setPageTitle(title + ' | ') + else + $.oc.layout.setPageTitle(title) + } + + CmsPage.prototype.updateLayouts = function(form) { + $(form).request('onGetTemplateList', { + success: function(data) { + $('#cms-master-tabs > .tab-content select[name="settings[layout]"]').each(function() { + var + $select = $(this), + value = $select.val() + + $select.find('option').remove() + $.each(data.layouts, function(layoutFile, layoutName){ + $select.append($('
    + + + + + + + + + + +
    diff --git a/plugins/indikator/devtools/controllers/editor/_form_page.htm b/plugins/indikator/devtools/controllers/editor/_form_page.htm new file mode 100644 index 0000000..918a0ae --- /dev/null +++ b/plugins/indikator/devtools/controllers/editor/_form_page.htm @@ -0,0 +1,15 @@ + 'layout', + 'data-change-monitor' => 'true', + 'data-window-close-confirm' => e(trans('backend::lang.form.confirm_tab_close')), + 'data-inspector-external-parameters' => true + ]) ?> + render() ?> + + + + + + + + diff --git a/plugins/indikator/devtools/controllers/editor/_sidepanel.htm b/plugins/indikator/devtools/controllers/editor/_sidepanel.htm new file mode 100644 index 0000000..eb4f705 --- /dev/null +++ b/plugins/indikator/devtools/controllers/editor/_sidepanel.htm @@ -0,0 +1,14 @@ +
    +
    +
    +
    + widget->assetList->render() ?> +
    +
    +
    +
    diff --git a/plugins/indikator/devtools/controllers/editor/index.htm b/plugins/indikator/devtools/controllers/editor/index.htm new file mode 100644 index 0000000..dd35315 --- /dev/null +++ b/plugins/indikator/devtools/controllers/editor/index.htm @@ -0,0 +1,30 @@ + + fatalError): ?> + makePartial('sidepanel') ?> + + + + + fatalError): ?> +
    + +
    +
    + +
    +
    + +
    +
    + +

    fatalError)) ?>

    + + diff --git a/plugins/indikator/devtools/formwidgets/Help.php b/plugins/indikator/devtools/formwidgets/Help.php new file mode 100644 index 0000000..ddf69a6 --- /dev/null +++ b/plugins/indikator/devtools/formwidgets/Help.php @@ -0,0 +1,30 @@ +fillFromConfig([ + 'content' + ]); + } + + public function render() + { + $this->prepareVars(); + + return $this->makePartial('help'); + } + + protected function prepareVars() + { + $this->vars['content'] = $this->content; + } +} diff --git a/plugins/indikator/devtools/formwidgets/help/partials/_help.htm b/plugins/indikator/devtools/formwidgets/help/partials/_help.htm new file mode 100644 index 0000000..39b2c47 --- /dev/null +++ b/plugins/indikator/devtools/formwidgets/help/partials/_help.htm @@ -0,0 +1,88 @@ + + + +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    + diff --git a/plugins/indikator/devtools/lang/en/lang.php b/plugins/indikator/devtools/lang/en/lang.php new file mode 100644 index 0000000..5c16666 --- /dev/null +++ b/plugins/indikator/devtools/lang/en/lang.php @@ -0,0 +1,72 @@ + [ + 'name' => 'Developer Tools', + 'description' => 'Useful features for developers.', + 'author' => 'Gergő Szabó' + ], + 'editor' => [ + 'menu_label' => 'Code editor', + 'plugins' => 'Plugins', + 'permission' => 'Use the code editor' + ], + 'help' => [ + 'menu_label' => 'Developer Tools', + 'menu_description' => 'Settings of developer features.', + 'tab' => 'Help', + 'cms' => 'CMS', + 'pages' => 'Pages', + 'partials' => 'Partials', + 'layouts' => 'Layouts', + 'content' => 'Content', + 'ajax' => 'AJAX', + 'functions' => 'Functions', + 'tags' => 'Tags', + 'filters' => 'Filters', + 'database' => 'Database', + 'basic' => 'Basic', + 'queries' => 'Queries', + 'plugins' => 'Plugins', + 'registration' => 'Registration', + 'version_history' => 'Version history', + 'building_components' => 'Building components', + 'settings_config' => 'Settings & Config', + 'localization' => 'Localization', + 'task_scheduling' => 'Task scheduling', + 'extending_plugins' => 'Extending plugins', + 'backend' => 'Backend', + 'controllers_ajax' => 'Controllers & AJAX', + 'views_partials' => 'Views & Partials', + 'widgets' => 'Widgets', + 'forms' => 'Forms', + 'lists' => 'Lists', + 'relations' => 'Relations', + 'sorting_records' => 'Sorting records', + 'importing_exporting' => 'Importing & Exporting', + 'users_permissions' => 'Users & Permissions', + 'user_interface_guide' => 'User interface guide', + 'services' => 'Services', + 'application' => 'Application', + 'behaviors' => 'Behaviors', + 'events' => 'Events', + 'forms_html' => 'Forms & Html', + 'mail' => 'Mail', + 'request_input' => 'Request & Input', + 'response_view' => 'Response & View', + 'router' => 'Router', + 'session' => 'Session', + 'validation' => 'Validation', + 'permission' => 'Manage settings' + ], + 'form' => [ + 'wysiwyg_label' => 'Wysiwyg Editor', + 'wysiwyg_enabled' => 'Enabled on the Content page', + 'help_label' => 'Help', + 'help_enabled' => 'Enable the Help tab on the CMS pages', + 'select_none' => '-- None --', + 'select_superuser' => 'Show it for the Superusers', + 'select_admingroup' => 'Show it for the following admin group', + 'select_adminid' => 'Show it for the following administrator', + ] +]; diff --git a/plugins/indikator/devtools/lang/hu/lang.php b/plugins/indikator/devtools/lang/hu/lang.php new file mode 100644 index 0000000..1619fc6 --- /dev/null +++ b/plugins/indikator/devtools/lang/hu/lang.php @@ -0,0 +1,72 @@ + [ + 'name' => 'Fejlesztői eszközök', + 'description' => 'Hasznos szolgáltatások fejlesztőknek.', + 'author' => 'Szabó Gergő' + ], + 'editor' => [ + 'menu_label' => 'Kódszerkesztő', + 'plugins' => 'Bővítmények', + 'permission' => 'Szerkesztő használata' + ], + 'help' => [ + 'menu_label' => 'Fejlesztőknek', + 'menu_description' => 'Szolgáltatások és lehetőségek beállítása.', + 'tab' => 'Súgó', + 'cms' => 'Testreszabás', + 'pages' => 'Lapok', + 'partials' => 'Részlapok', + 'layouts' => 'Elrendezések', + 'content' => 'Tartalom', + 'ajax' => 'AJAX', + 'functions' => 'Függvények', + 'tags' => 'Tag-ek', + 'filters' => 'Filterek', + 'database' => 'Adatbázis', + 'basic' => 'Alapok', + 'queries' => 'Lekérdezések', + 'plugins' => 'Bővítmények', + 'registration' => 'Regisztrálás', + 'version_history' => 'Verzió előzmények', + 'building_components' => 'Komponensek', + 'settings_config' => 'Beállítások', + 'localization' => 'Többnyelvűsítés', + 'task_scheduling' => 'Időzítés', + 'extending_plugins' => 'Kiegészítés', + 'backend' => 'Admin', + 'controllers_ajax' => 'Kontroller és AJAX', + 'views_partials' => 'Részlapok', + 'widgets' => 'Widgetek', + 'forms' => 'Űrlapok', + 'lists' => 'Listák', + 'relations' => 'Kapcsolatok', + 'sorting_records' => 'Elemek rendezése', + 'importing_exporting' => 'Import és export', + 'users_permissions' => 'Jogosultságok', + 'user_interface_guide' => 'Felhasználói felület', + 'services' => 'Szolgáltatások', + 'application' => 'Alkalmazás', + 'behaviors' => 'Viselkedések', + 'events' => 'Események', + 'forms_html' => 'Űrlapok és HTML', + 'mail' => 'Levelezés', + 'request_input' => 'Űrlap értékek', + 'response_view' => 'Válasz megjelenítés', + 'router' => 'Router kezelés', + 'session' => 'Munkamenet', + 'validation' => 'Ellenőrzés', + 'permission' => 'Beállítások kezelése' + ], + 'form' => [ + 'wysiwyg_label' => 'Szövegszerkesztő', + 'wysiwyg_enabled' => 'Engedélyezés a Tartalom oldalon', + 'help_label' => 'Súgó', + 'help_enabled' => 'Engedélyezés a Testreszabás aloldalakon', + 'select_none' => '-- nincs --', + 'select_superuser' => 'Szuperadminok láthatják', + 'select_admingroup' => 'A következő admin csoport tagjai láthatják', + 'select_adminid' => 'A következő admin felhasználó láthatja' + ] +]; diff --git a/plugins/indikator/devtools/models/Settings.php b/plugins/indikator/devtools/models/Settings.php new file mode 100644 index 0000000..879b2a8 --- /dev/null +++ b/plugins/indikator/devtools/models/Settings.php @@ -0,0 +1,63 @@ + 'indikator.devtools::lang.form.select_none']; + + public function getHelpAdmingroupOptions() + { + $result = $this->selectList; + $sql = Db::table('backend_user_groups')->orderBy('name', 'asc')->get()->all(); + + foreach ($sql as $item) { + $result[$item->id] = $item->name.' ('.Db::table('backend_users_groups')->where('user_group_id', $item->id)->count().')'; + } + + return $result; + } + + public function getHelpAdminidOptions() + { + $result = $this->selectList; + $sql = Db::table('backend_users')->orderBy('login', 'asc')->get()->all(); + + foreach ($sql as $item) { + $result[$item->id] = $item->login.' ('.$item->email.')'; + } + + return $result; + } + + public function getWysiwygAdmingroupOptions() + { + $result = $this->selectList; + $sql = Db::table('backend_user_groups')->orderBy('name', 'asc')->get()->all(); + + foreach ($sql as $item) { + $result[$item->id] = $item->name.' ('.Db::table('backend_users_groups')->where('user_group_id', $item->id)->count().')'; + } + + return $result; + } + + public function getWysiwygAdminidOptions() + { + $result = $this->selectList; + $sql = Db::table('backend_users')->orderBy('login', 'asc')->get()->all(); + + foreach ($sql as $item) { + $result[$item->id] = $item->login.' ('.$item->email.')'; + } + + return $result; + } +} diff --git a/plugins/indikator/devtools/models/settings/fields.yaml b/plugins/indikator/devtools/models/settings/fields.yaml new file mode 100644 index 0000000..001c764 --- /dev/null +++ b/plugins/indikator/devtools/models/settings/fields.yaml @@ -0,0 +1,85 @@ +# =================================== +# Field Definitions +# =================================== + +fields: + + help_title: + label: indikator.devtools::lang.form.help_label + type: section + comment: '' + span: left + + wysiwyg_title: + label: indikator.devtools::lang.form.wysiwyg_label + type: section + comment: '' + span: right + + help_enabled: + label: indikator.devtools::lang.form.help_enabled + type: switch + default: false + span: left + + wysiwyg_enabled: + label: indikator.devtools::lang.form.wysiwyg_enabled + type: switch + default: false + span: right + + help_superuser: + label: indikator.devtools::lang.form.select_superuser + type: switch + default: false + trigger: + action: show + field: help_enabled + condition: checked + span: left + + wysiwyg_superuser: + label: indikator.devtools::lang.form.select_superuser + type: switch + default: false + trigger: + action: show + field: wysiwyg_enabled + condition: checked + span: right + + help_admingroup: + label: indikator.devtools::lang.form.select_admingroup + type: dropdown + trigger: + action: show + field: help_enabled + condition: checked + span: left + + wysiwyg_admingroup: + label: indikator.devtools::lang.form.select_admingroup + type: dropdown + trigger: + action: show + field: wysiwyg_enabled + condition: checked + span: right + + help_adminid: + label: indikator.devtools::lang.form.select_adminid + type: dropdown + trigger: + action: show + field: help_enabled + condition: checked + span: left + + wysiwyg_adminid: + label: indikator.devtools::lang.form.select_adminid + type: dropdown + trigger: + action: show + field: wysiwyg_enabled + condition: checked + span: right diff --git a/plugins/indikator/devtools/routes.php b/plugins/indikator/devtools/routes.php new file mode 100644 index 0000000..5bb4d11 --- /dev/null +++ b/plugins/indikator/devtools/routes.php @@ -0,0 +1,10 @@ +is_superuser == 1) { + echo phpinfo(); + } +}); diff --git a/plugins/indikator/devtools/updates/version.yaml b/plugins/indikator/devtools/updates/version.yaml new file mode 100644 index 0000000..821eae6 --- /dev/null +++ b/plugins/indikator/devtools/updates/version.yaml @@ -0,0 +1,17 @@ +1.0.0: First version of Developer Tools. +1.1.0: Edit plugins with the code editor. +1.1.1: Translate some English texts. +1.1.2: Fixed the Create file issue. +1.1.3: Added new icon for main navigation. +1.1.4: Show the PHP's configuration. +1.1.5: Minor code improvements and bugfix. +1.1.6: The top menu icon shows again. +1.1.7: Fixed the Create folder issue. +1.1.8: "!!! Updated for October 420+." +1.1.9: + - Updated the main navigation icon. + - Added last modified date. +1.2.0: The syntax highlighting works again! +1.2.1: Help links open in a new window. +1.2.2: Fixed the dependency bug in asset list. +1.2.3: The file delete operation works again. diff --git a/plugins/indikator/devtools/widgets/AssetList.php b/plugins/indikator/devtools/widgets/AssetList.php new file mode 100644 index 0000000..f0380de --- /dev/null +++ b/plugins/indikator/devtools/widgets/AssetList.php @@ -0,0 +1,709 @@ +alias = $alias; + $this->theme = Theme::getEditTheme(); + $this->selectionInputName = 'file'; + $this->assetExtensions = FileDefinitions::get('assetExtensions'); + + parent::__construct($controller, []); + $this->bindToController(); + + $this->checkUploadPostback(); + } + + /** + * @inheritDoc + */ + protected function loadAssets() + { + $this->addCss('css/assetlist.css'); + $this->addJs('js/assetlist.js'); + } + + /** + * Renders the widget. + * @return string + */ + public function render() + { + return $this->makePartial('body', [ + 'data' => $this->getData() + ]); + } + + // + // Event handlers + // + + public function onOpenDirectory() + { + $path = Input::get('path'); + if (!$this->validatePath($path)) { + throw new ApplicationException(Lang::get('cms::lang.asset.invalid_path')); + } + + $delay = Input::get('delay'); + if ($delay) { + usleep(1000000 * $delay); + } + + $this->putSession('currentPath', $path); + return [ + '#'.$this->getId('asset-list') => $this->makePartial('items', ['items' => $this->getData()]) + ]; + } + + public function onRefresh() + { + return [ + '#'.$this->getId('asset-list') => $this->makePartial('items', ['items' => $this->getData()]) + ]; + } + + public function onUpdate() + { + $this->extendSelection(); + + return $this->onRefresh(); + } + + public function onDeleteFiles() + { + $fileList = Request::input('file'); + $error = null; + $deleted = []; + + try { + $assetsPath = $this->getAssetsPath(); + + foreach ($fileList as $path => $selected) { + if ($selected) { + if (!$this->validatePath($path)) { + throw new ApplicationException(Lang::get('cms::lang.asset.invalid_path')); + } + + $fullPath = $assetsPath.'/'.$path; + if (File::exists($fullPath)) { + if (!File::isDirectory($fullPath)) { + if (!@File::delete($fullPath)) { + throw new ApplicationException(Lang::get( + 'cms::lang.asset.error_deleting_file', + ['name' => $path] + )); + } + } + else { + $empty = File::isDirectoryEmpty($fullPath); + if ($empty === false) { + throw new ApplicationException(Lang::get( + 'cms::lang.asset.error_deleting_dir_not_empty', + ['name' => $path] + )); + } + + if (!@rmdir($fullPath)) { + throw new ApplicationException(Lang::get( + 'cms::lang.asset.error_deleting_dir', + ['name' => $path] + )); + } + } + + $deleted[] = $path; + $this->removeSelection($path); + } + } + } + } + catch (Exception $ex) { + $error = $ex->getMessage(); + } + + return [ + 'deleted' => $deleted, + 'error' => $error + ]; + } + + public function onLoadRenamePopup() + { + $path = Input::get('renamePath'); + if (!$this->validatePath($path)) { + throw new ApplicationException(Lang::get('cms::lang.asset.invalid_path')); + } + + $this->vars['originalPath'] = $path; + $this->vars['name'] = basename($path); + + return $this->makePartial('rename_form'); + } + + public function onApplyName() + { + $newName = trim(Input::get('name')); + if (!strlen($newName)) { + throw new ApplicationException(Lang::get('cms::lang.asset.name_cant_be_empty')); + } + + if (!$this->validatePath($newName)) { + throw new ApplicationException(Lang::get('cms::lang.asset.invalid_path')); + } + + if (!$this->validateName($newName)) { + throw new ApplicationException(Lang::get('cms::lang.asset.invalid_name')); + } + + $originalPath = Input::get('originalPath'); + if (!$this->validatePath($originalPath)) { + throw new ApplicationException(Lang::get('cms::lang.asset.invalid_path')); + } + + $originalFullPath = $this->getFullPath($originalPath); + if (!file_exists($originalFullPath)) { + throw new ApplicationException(Lang::get('cms::lang.asset.original_not_found')); + } + + if (!is_dir($originalFullPath) && !$this->validateFileType($newName)) { + throw new ApplicationException(Lang::get( + 'cms::lang.asset.type_not_allowed', + ['allowed_types' => implode(', ', $this->assetExtensions)] + )); + } + + $newFullPath = $this->getFullPath(dirname($originalPath).'/'.$newName); + if (file_exists($newFullPath) && $newFullPath !== $originalFullPath) { + throw new ApplicationException(Lang::get('cms::lang.asset.already_exists')); + } + + if (!@rename($originalFullPath, $newFullPath)) { + throw new ApplicationException(Lang::get('cms::lang.asset.error_renaming')); + } + + return [ + '#'.$this->getId('asset-list') => $this->makePartial('items', ['items' => $this->getData()]) + ]; + } + + public function onLoadNewDirPopup() + { + return $this->makePartial('new_dir_form'); + } + + public function onNewDirectory() + { + $newName = trim(Input::get('name')); + if (!strlen($newName)) { + throw new ApplicationException(Lang::get('cms::lang.asset.name_cant_be_empty')); + } + + if (!$this->validatePath($newName)) { + throw new ApplicationException(Lang::get('cms::lang.asset.invalid_path')); + } + + if (!$this->validateName($newName)) { + throw new ApplicationException(Lang::get('cms::lang.asset.invalid_name')); + } + + $newFullPath = $this->getCurrentPath().'/'.$newName; + if (file_exists($newFullPath)) { + throw new ApplicationException(Lang::get('cms::lang.asset.already_exists')); + } + + if (!File::makeDirectory($newFullPath)) { + throw new ApplicationException(Lang::get( + 'cms::lang.cms_object.error_creating_directory', + ['name' => $newName] + )); + } + + return [ + '#'.$this->getId('asset-list') => $this->makePartial('items', ['items' => $this->getData()]) + ]; + } + + public function onLoadMovePopup() + { + $fileList = Request::input('file'); + $directories = []; + + $selectedList = array_filter($fileList, function ($value) { + return $value == 1; + }); + + $this->listDestinationDirectories($directories, $selectedList); + + $this->vars['directories'] = $directories; + $this->vars['selectedList'] = base64_encode(json_encode(array_keys($selectedList))); + + return $this->makePartial('move_form'); + } + + public function onMove() + { + $selectedList = Input::get('selectedList'); + if (!strlen($selectedList)) { + throw new ApplicationException(Lang::get('cms::lang.asset.selected_files_not_found')); + } + + $destinationDir = Input::get('dest'); + if (!strlen($destinationDir)) { + throw new ApplicationException(Lang::get('cms::lang.asset.select_destination_dir')); + } + + $destinationFullPath = $this->getFullPath($destinationDir); + if (!file_exists($destinationFullPath) || !is_dir($destinationFullPath)) { + throw new ApplicationException(Lang::get('cms::lang.asset.destination_not_found')); + } + + $list = @json_decode(@base64_decode($selectedList)); + if ($list === false) { + throw new ApplicationException(Lang::get('cms::lang.asset.selected_files_not_found')); + } + + foreach ($list as $path) { + if (!$this->validatePath($path)) { + throw new ApplicationException(Lang::get('cms::lang.asset.invalid_path')); + } + + $basename = basename($path); + $originalFullPath = $this->getFullPath($path); + $newFullPath = rtrim($destinationFullPath, '/').'/'.$basename; + $safeDir = $this->getAssetsPath(); + + if ($originalFullPath == $newFullPath) { + continue; + } + + if (is_file($originalFullPath)) { + if (!@File::move($originalFullPath, $newFullPath)) { + throw new ApplicationException(Lang::get( + 'cms::lang.asset.error_moving_file', + ['file' => $basename] + )); + } + } + elseif (is_dir($originalFullPath)) { + if (!@File::copyDirectory($originalFullPath, $newFullPath)) { + throw new ApplicationException(Lang::get( + 'cms::lang.asset.error_moving_directory', + ['dir' => $basename] + )); + } + + if (strpos($originalFullPath, '../') !== false) { + throw new ApplicationException(Lang::get( + 'cms::lang.asset.error_deleting_directory', + ['dir' => $basename] + )); + } + + if (strpos($originalFullPath, $safeDir) !== 0) { + throw new ApplicationException(Lang::get( + 'cms::lang.asset.error_deleting_directory', + ['dir' => $basename] + )); + } + + if (!@File::deleteDirectory($originalFullPath)) { + throw new ApplicationException(Lang::get( + 'cms::lang.asset.error_deleting_directory', + ['dir' => $basename] + )); + } + } + } + + return [ + '#'.$this->getId('asset-list') => $this->makePartial('items', ['items' => $this->getData()]) + ]; + } + + public function onSearch() + { + $this->setSearchTerm(Input::get('search')); + $this->extendSelection(); + + return $this->onRefresh(); + } + + /* + * Methods for the internal use + */ + + protected function getData() + { + $assetsPath = $this->getAssetsPath(); + + if (!file_exists($assetsPath) || !is_dir($assetsPath)) { + if (!File::makeDirectory($assetsPath)) { + throw new ApplicationException(Lang::get( + 'cms::lang.cms_object.error_creating_directory', + ['name' => $assetsPath] + )); + } + } + + $searchTerm = Str::lower($this->getSearchTerm()); + + if (!strlen($searchTerm)) { + $currentPath = $this->getCurrentPath(); + return $this->getDirectoryContents( + new DirectoryIterator($currentPath) + ); + } + + return $this->findFiles(); + } + + protected function getAssetsPath() + { + return base_path().'/plugins'; + } + + protected function getThemeFileUrl($path) + { + return Url::to('plugins'.$path); + } + + public function getCurrentRelativePath() + { + $path = $this->getSession('currentPath', '/'); + + if (!$this->validatePath($path)) { + return null; + } + + if ($path == '.') { + return null; + } + + return ltrim($path, '/'); + } + + protected function getCurrentPath() + { + $assetsPath = $this->getAssetsPath(); + + $path = $assetsPath.'/'.$this->getCurrentRelativePath(); + if (!is_dir($path)) { + return $assetsPath; + } + + return $path; + } + + protected function getRelativePath($path) + { + $prefix = $this->getAssetsPath(); + + if (substr($path, 0, strlen($prefix)) == $prefix) { + $path = substr($path, strlen($prefix)); + } + + return $path; + } + + protected function getFullPath($path) + { + return $this->getAssetsPath().'/'.ltrim($path, '/'); + } + + protected function validatePath($path) + { + if (!preg_match('/^[0-9a-z\.\s_\-\/]+$/i', $path)) { + return false; + } + + if (strpos($path, '..') !== false || strpos($path, './') !== false) { + return false; + } + + return true; + } + + protected function validateName($name) + { + if (!preg_match('/^[0-9a-z\.\s_\-]+$/i', $name)) { + return false; + } + + if (strpos($name, '..') !== false) { + return false; + } + + return true; + } + + protected function getDirectoryContents($dir) + { + $editableAssetTypes = Asset::getEditableExtensions(); + + $result = $files = []; + + foreach ($dir as $node) { + if (substr($node->getFileName(), 0, 1) == '.') { + continue; + } + + if ($node->isDir() && !$node->isDot()) { + $result[$node->getFilename()] = (object)[ + 'type' => 'directory', + 'path' => File::normalizePath($this->getRelativePath($node->getPathname())), + 'name' => $node->getFilename(), + 'editable' => false + ]; + } + elseif ($node->isFile()) { + $files[] = (object)[ + 'type' => 'file', + 'path' => File::normalizePath($this->getRelativePath($node->getPathname())), + 'name' => $node->getFilename(), + 'editable' => in_array(strtolower($node->getExtension()), $editableAssetTypes) + ]; + } + } + + foreach ($files as $file) { + $result[] = $file; + } + + return $result; + } + + protected function listDestinationDirectories(&$result, $excludeList, $startDir = null, $level = 0) + { + if ($startDir === null) { + $startDir = $this->getAssetsPath(); + + $result['/'] = 'assets'; + $level = 1; + } + + $dirs = new DirectoryIterator($startDir); + foreach ($dirs as $node) { + if (substr($node->getFileName(), 0, 1) == '.') { + continue; + } + + if ($node->isDir() && !$node->isDot()) { + $fullPath = $node->getPathname(); + $relativePath = $this->getRelativePath($fullPath); + if (array_key_exists($relativePath, $excludeList)) { + continue; + } + + $result[$relativePath] = str_repeat(' ', $level * 4).$node->getFilename(); + + $this->listDestinationDirectories($result, $excludeList, $fullPath, $level+1); + } + } + } + + protected function getSearchTerm() + { + return $this->searchTerm !== false ? $this->searchTerm : $this->getSession('search'); + } + + protected function isSearchMode() + { + return strlen($this->getSearchTerm()); + } + + protected function getUpPath() + { + $path = $this->getCurrentRelativePath(); + if (!strlen(rtrim(ltrim($path, '/'), '/'))) { + return null; + } + + return dirname($path); + } + + /** + * Check for valid asset file extension + * @param string + * @return bool + */ + protected function validateFileType($name) + { + $extension = strtolower(File::extension($name)); + + if (!in_array($extension, $this->assetExtensions)) { + return false; + } + + return true; + } + + /** + * Checks the current request to see if it is a postback containing a file upload + * for this particular widget. + */ + protected function checkUploadPostback() + { + $fileName = null; + + try { + $uploadedFile = Input::file('file_data'); + + if (!is_object($uploadedFile)) { + return; + } + + $fileName = $uploadedFile->getClientOriginalName(); + + /* + * Check valid upload + */ + if (!$uploadedFile->isValid()) { + throw new ApplicationException(Lang::get('cms::lang.asset.file_not_valid')); + } + + /* + * Check file size + */ + $maxSize = UploadedFile::getMaxFilesize(); + if ($uploadedFile->getSize() > $maxSize) { + throw new ApplicationException(Lang::get( + 'cms::lang.asset.too_large', + ['max_size' => File::sizeToString($maxSize)] + )); + } + + /* + * Check for valid file extensions + */ + if (!$this->validateFileType($fileName)) { + throw new ApplicationException(Lang::get( + 'cms::lang.asset.type_not_allowed', + ['allowed_types' => implode(', ', $this->assetExtensions)] + )); + } + + /* + * Accept the uploaded file + */ + $uploadedFile->move($this->getCurrentPath(), $uploadedFile->getClientOriginalName()); + + die('success'); + } + catch (Exception $ex) { + $message = $fileName !== null + ? Lang::get('cms::lang.asset.error_uploading_file', ['name' => $fileName, 'error' => $ex->getMessage()]) + : $ex->getMessage(); + + die($message); + } + } + + protected function setSearchTerm($term) + { + $this->searchTerm = trim($term); + $this->putSession('search', $this->searchTerm); + } + + protected function findFiles() + { + $iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($this->getAssetsPath(), RecursiveDirectoryIterator::SKIP_DOTS), + RecursiveIteratorIterator::SELF_FIRST, + RecursiveIteratorIterator::CATCH_GET_CHILD + ); + + $editableAssetTypes = Asset::getEditableExtensions(); + $searchTerm = Str::lower($this->getSearchTerm()); + $words = explode(' ', $searchTerm); + + $result = []; + foreach ($iterator as $item) { + if (!$item->isDir()) { + if (substr($item->getFileName(), 0, 1) == '.') { + continue; + } + + $path = $this->getRelativePath($item->getPathname()); + + if ($this->pathMatchesSearch($words, $path)) { + $result[] = (object)[ + 'type' => 'file', + 'path' => File::normalizePath($path), + 'name' => $item->getFilename(), + 'editable' => in_array(strtolower($item->getExtension()), $editableAssetTypes) + ]; + } + } + } + + return $result; + } + + protected function pathMatchesSearch(&$words, $path) + { + foreach ($words as $word) { + $word = trim($word); + if (!strlen($word)) { + continue; + } + + if (!Str::contains(Str::lower($path), $word)) { + return false; + } + } + + return true; + } +} diff --git a/plugins/indikator/devtools/widgets/assetlist/assets/css/assetlist.css b/plugins/indikator/devtools/widgets/assetlist/assets/css/assetlist.css new file mode 100644 index 0000000..c748bb3 --- /dev/null +++ b/plugins/indikator/devtools/widgets/assetlist/assets/css/assetlist.css @@ -0,0 +1,244 @@ +.control-assetlist p.no-data { + padding: 22px; + margin: 0; + color: #666666; + font-size: 14px; + text-align: center; + font-weight: 400; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} +.control-assetlist p.parent, +.control-assetlist ul li { + font-weight: 300; + line-height: 150%; + margin-bottom: 0; +} +.control-assetlist p.parent.active a, +.control-assetlist ul li.active a { + background: #dddddd; + position: relative; +} +.control-assetlist p.parent.active a:after, +.control-assetlist ul li.active a:after { + position: absolute; + height: 100%; + width: 4px; + left: 0; + top: 0; + background: #e67e22; + display: block; + content: ' '; +} +.control-assetlist p.parent a.link, +.control-assetlist ul li a.link { + display: block; + position: relative; + word-wrap: break-word; + padding: 10px 50px 10px 20px; + outline: none; + font-weight: 400; + color: #405261; + font-size: 14px; +} +.control-assetlist p.parent a.link:hover, +.control-assetlist ul li a.link:hover, +.control-assetlist p.parent a.link:focus, +.control-assetlist ul li a.link:focus, +.control-assetlist p.parent a.link:active, +.control-assetlist ul li a.link:active { + text-decoration: none; +} +.control-assetlist p.parent a.link span, +.control-assetlist ul li a.link span { + display: block; +} +.control-assetlist p.parent a.link span.description, +.control-assetlist ul li a.link span.description { + color: #8f8f8f; + font-size: 12px; + font-weight: 400; + word-wrap: break-word; +} +.control-assetlist p.parent a.link span.description strong, +.control-assetlist ul li a.link span.description strong { + color: #405261; + font-weight: 400; +} +.control-assetlist p.parent.directory a.link, +.control-assetlist ul li.directory a.link, +.control-assetlist p.parent.parent a.link, +.control-assetlist ul li.parent a.link { + padding-left: 40px; +} +.control-assetlist p.parent.directory a.link:after, +.control-assetlist ul li.directory a.link:after, +.control-assetlist p.parent.parent a.link:after, +.control-assetlist ul li.parent a.link:after { + display: block; + position: absolute; + width: 10px; + height: 10px; + top: 10px; + left: 20px; + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + text-decoration: inherit; + -webkit-font-smoothing: antialiased; + content: "\f07b"; + color: #a1aab1; + font-size: 14px; +} +.control-assetlist p.parent.parent a.link, +.control-assetlist ul li.parent a.link { + padding-left: 41px; + background-color: #ffffff; + word-wrap: break-word; +} +.control-assetlist p.parent.parent a.link:before, +.control-assetlist ul li.parent a.link:before { + content: ''; + display: block; + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 1px; + background: #ecf0f1; +} +.control-assetlist p.parent.parent a.link:after, +.control-assetlist ul li.parent a.link:after { + font-size: 13px; + color: #34495e; + width: 18px; + height: 18px; + top: 11px; + left: 22px; + opacity: 0.5; + filter: alpha(opacity=50); + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + text-decoration: inherit; + -webkit-font-smoothing: antialiased; + content: "\f053"; +} +.control-assetlist p.parent a.link:hover { + background: #dddddd !important; +} +.control-assetlist p.parent a.link:hover:after { + opacity: 1; + filter: alpha(opacity=100); +} +.control-assetlist p.parent a.link:hover:before { + display: none; +} +.control-assetlist ul { + padding: 0; + margin: 0; +} +.control-assetlist ul li { + font-weight: 300; + line-height: 150%; + position: relative; + list-style: none; +} +.control-assetlist ul li.active a.link, +.control-assetlist ul li a.link:hover { + background: #dddddd; +} +.control-assetlist ul li.active a.link { + position: relative; +} +.control-assetlist ul li.active a.link:after { + position: absolute; + height: 100%; + width: 4px; + left: 0; + top: 0; + background: #e67e22; + display: block; + content: ' '; +} +.control-assetlist ul li div.controls { + position: absolute; + right: 45px; + top: 10px; +} +.control-assetlist ul li div.controls .dropdown { + width: 14px; + height: 21px; +} +.control-assetlist ul li div.controls .dropdown.open a.control { + display: block!important; +} +.control-assetlist ul li div.controls .dropdown.open a.control:before { + visibility: visible; + display: block; +} +.control-assetlist ul li div.controls a.control { + color: #405261; + font-size: 14px; + visibility: hidden; + overflow: hidden; + width: 14px; + height: 21px; + display: none; + text-decoration: none; + cursor: pointer; + opacity: 0.5; + filter: alpha(opacity=50); +} +.control-assetlist ul li div.controls a.control:before { + visibility: visible; + display: block; + margin-right: 0; +} +.control-assetlist ul li div.controls a.control:hover { + opacity: 1; + filter: alpha(opacity=100); +} +.control-assetlist ul li:hover { + background: #dddddd; +} +.control-assetlist ul li:hover div.controls, +.control-assetlist ul li:hover a.control { + display: block!important; +} +.control-assetlist ul li:hover div.controls > a.control, +.control-assetlist ul li:hover a.control > a.control { + display: block!important; +} +.control-assetlist ul li .checkbox { + position: absolute; + top: -5px; + right: -5px; +} +.control-assetlist ul li .checkbox label { + margin-right: 0; +} +.control-assetlist ul li .checkbox label:before { + border-color: #cccccc; +} +.control-assetlist div.list-container { + position: relative; + -webkit-transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); +} +.control-assetlist div.list-container.animate ul { + -webkit-transition: all 0.2s ease; + transition: all 0.2s ease; +} +.control-assetlist div.list-container.goForward ul { + -webkit-transform: translate(-350px, 0); + -ms-transform: translate(-350px, 0); + transform: translate(-350px, 0); +} +.control-assetlist div.list-container.goBackward ul { + -webkit-transform: translate(350px, 0); + -ms-transform: translate(350px, 0); + transform: translate(350px, 0); +} diff --git a/plugins/indikator/devtools/widgets/assetlist/assets/js/assetlist.js b/plugins/indikator/devtools/widgets/assetlist/assets/js/assetlist.js new file mode 100644 index 0000000..4fb3d41 --- /dev/null +++ b/plugins/indikator/devtools/widgets/assetlist/assets/js/assetlist.js @@ -0,0 +1,184 @@ +/* + * Asset list + */ ++function ($) { "use strict"; + + var AssetList = function (form, alias) { + this.$form = $(form) + this.alias = alias + + + this.$form.on('ajaxSuccess', $.proxy(this.onAjaxSuccess, this)) + this.$form.on('click', 'ul.list > li.directory > a', $.proxy(this.onDirectoryClick, this)) + this.$form.on('click', 'ul.list > li.file > a', $.proxy(this.onFileClick, this)) + this.$form.on('click', 'p.parent > a', $.proxy(this.onDirectoryClick, this)) + this.$form.on('click', 'a[data-control=delete-asset]', $.proxy(this.onDeleteClick, this)) + this.$form.on('oc.list.setActiveItem', $.proxy(this.onSetActiveItem, this)) + + this.setupUploader() + } + + // Event handlers + // ================= + + AssetList.prototype.onDirectoryClick = function(e) { + this.gotoDirectory( + $(e.currentTarget).data('path'), + $(e.currentTarget).parent().hasClass('parent') + ) + + return false; + } + + AssetList.prototype.gotoDirectory = function(path, gotoParent) { + var $container = $('div.list-container', this.$form), + self = this + + if (gotoParent !== undefined && gotoParent) + $container.addClass('goBackward') + else + $container.addClass('goForward') + + $.oc.stripeLoadIndicator.show() + this.$form.request(this.alias+'::onOpenDirectory', { + data: { + path: path, + d: 0.2 + }, + complete: function() { + self.updateUi() + $container.trigger('oc.scrollbar.gotoStart') + }, + error: function(jqXHR, textStatus, errorThrown) { + $container.removeClass('goForward goBackward') + alert(jqXHR.responseText.length ? jqXHR.responseText : jqXHR.statusText) + } + }).always(function(){ + $.oc.stripeLoadIndicator.hide() + }) + } + + AssetList.prototype.onDeleteClick = function(e) { + var $el = $(e.currentTarget), + self = this + + if (!confirm($el.data('confirmation'))) + return false + + this.$form.request(this.alias+'::onDeleteFiles', { + success: function(data) { + if (data.error !== undefined && $.type(data.error) === 'string' && data.error.length) + $.oc.flashMsg({text: data.error, 'class': 'error'}) + }, + complete: function() { + self.refresh() + } + }) + + return false + } + + AssetList.prototype.onAjaxSuccess = function() { + this.updateUi() + } + + AssetList.prototype.onUploadFail = function(file, message) { + if (file.xhr.status === 413) { + message = 'Server rejected the file because it was too large, try increasing post_max_size'; + } + if (!message) { + message = 'Error uploading file' + } + + $.oc.alert(message) + + this.refresh() + } + + AssetList.prototype.onUploadSuccess = function(file, data) { + if (data !== 'success') { + $.oc.alert(data) + } + } + + AssetList.prototype.onUploadComplete = function(file, data) { + $.oc.stripeLoadIndicator.hide() + this.refresh() + } + + AssetList.prototype.onUploadStart = function() { + $.oc.stripeLoadIndicator.show() + } + + AssetList.prototype.onFileClick = function(event) { + var $link = $(event.currentTarget), + $li = $link.parent() + + var e = $.Event('open.oc.list', {relatedTarget: $li.get(0), clickEvent: event}) + this.$form.trigger(e, this) + + if (e.isDefaultPrevented()) + return false; + } + + AssetList.prototype.onSetActiveItem = function(event, dataId) { + $('ul li.file', this.$form).removeClass('active') + if (dataId) + $('ul li.file[data-id="'+dataId+'"]', this.$form).addClass('active') + } + + // Service functions + // ================= + + AssetList.prototype.updateUi = function() { + $('button[data-control=asset-tools]', self.$form).trigger('oc.triggerOn.update') + } + + AssetList.prototype.refresh = function() { + var self = this; + + this.$form.request(this.alias+'::onRefresh', { + complete: function() { + self.updateUi() + } + }) + } + + AssetList.prototype.setupUploader = function() { + var self = this, + $link = $('[data-control="upload-assets"]', this.$form), + uploaderOptions = { + method: 'POST', + url: window.location, + paramName: 'file_data', + previewsContainer: $('
    ').get(0), + clickable: $link.get(0), + timeout: 0, + headers: {} + } + + /* + * Add CSRF token to headers + */ + var token = $('meta[name="csrf-token"]').attr('content') + if (token) { + uploaderOptions.headers['X-CSRF-TOKEN'] = token + } + + var dropzone = new Dropzone($('
    ').get(0), uploaderOptions) + dropzone.on('error', $.proxy(self.onUploadFail, self)) + dropzone.on('success', $.proxy(self.onUploadSuccess, self)) + dropzone.on('complete', $.proxy(self.onUploadComplete, self)) + dropzone.on('sending', function(file, xhr, formData) { + $.each(self.$form.serializeArray(), function (index, field) { + formData.append(field.name, field.value) + }) + xhr.setRequestHeader('X-OCTOBER-REQUEST-HANDLER', self.alias + '::onUpload') + self.onUploadStart() + }) + } + + $(document).ready(function(){ + new AssetList($('#asset-list-container').closest('form'), $('#asset-list-container').data('alias')) + }) +}(window.jQuery); diff --git a/plugins/indikator/devtools/widgets/assetlist/assets/less/assetlist.less b/plugins/indikator/devtools/widgets/assetlist/assets/less/assetlist.less new file mode 100644 index 0000000..a8070d3 --- /dev/null +++ b/plugins/indikator/devtools/widgets/assetlist/assets/less/assetlist.less @@ -0,0 +1,236 @@ +@import "../../../../../backend/assets/less/core/boot.less"; + +.control-assetlist { + p.no-data { + padding: 22px; + margin: 0; + color: @color-filelist-norecords-text; + font-size: 14px; + text-align: center; + font-weight: 400; + .border-radius(@border-radius-base); + } + + p.parent, ul li { + font-weight: 300; + line-height: 150%; + margin-bottom: 0; + + &.active a { + background: @color-list-active; + position: relative; + &:after { + position: absolute; + height: 100%; + width: 4px; + left: 0; + top: 0; + background: @color-list-active-border; + display: block; + content: ' '; + } + } + + a.link { + display: block; + position: relative; + word-wrap: break-word; + padding: 10px 50px 10px 20px; + outline: none; + font-weight: 400; + color: @color-text-title; + font-size: 14px; + + &:hover, &:focus, &:active {text-decoration: none;} + + span { + display: block; + + &.description { + color: @color-text-description; + font-size: 12px; + font-weight: 400; + word-wrap: break-word; + + strong { + color: @color-text-title; + font-weight: 400; + } + } + } + } + + &.directory, &.parent { + a.link { + padding-left: 40px; + + &:after { + display: block; + position: absolute; + width: 10px; + height: 10px; + top: 10px; + left: 20px; + .icon(@folder); + color: @color-list-icon; + font-size: 14px; + } + } + } + + &.parent { + a.link { + padding-left: 41px; + background-color: @color-list-parent-bg; + word-wrap: break-word; + + &:before { + content: ''; + height: 1px; + display: block; + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 1px; + background: #ecf0f1; + } + + + &:after { + font-size: 13px; + color: @color-list-nav-arrow; + width: 18px; + height: 18px; + top: 11px; + left: 22px; + .opacity(0.5); + .icon(@chevron-left); + } + } + } + } + + p.parent a.link:hover { + background: @color-list-active!important; + + &:after { + .opacity(1); + } + + &:before { + display: none; + } + } + + ul { + padding: 0; + margin: 0; + + li { + font-weight: 300; + line-height: 150%; + position: relative; + list-style: none; + + &.active a.link, a.link:hover {background: @color-list-active;} + &.active a.link { + position: relative; + &:after { + position: absolute; + height: 100%; + width: 4px; + left: 0; + top: 0; + background: @color-list-active-border; + display: block; + content: ' '; + } + } + + div.controls { + position: absolute; + right: 45px; + top: 10px; + + .dropdown { + width: 14px; + height: 21px; + + &.open a.control { + display: block!important; + &:before { + visibility: visible; + display: block; + } + } + } + + a.control { + color: @color-text-title; + font-size: 14px; + visibility: hidden; + overflow: hidden; + width: 14px; + height: 21px; + display: none; + text-decoration: none; + cursor: pointer; + .opacity(0.5); + &:before { + visibility: visible; + display: block; + margin-right: 0; + } + + &:hover { + .opacity(1); + } + } + } + + &:hover { + background: @color-list-active; + div.controls, a.control { + display: block!important; + + > a.control { + display: block!important; + } + } + } + + .checkbox { + position: absolute; + top: -5px; + right: -5px; + + label { + margin-right: 0; + + &:before { + border-color: @color-filelist-cb-border; + } + } + } + } + } + + div.list-container { + position: relative; + .translate(0, 0); + + &.animate ul { + .transition(all 0.2s ease); + } + + &.goForward ul { + .translate(-350px, 0); + } + + &.goBackward ul { + .translate(350px, 0); + } + + } +} diff --git a/plugins/indikator/devtools/widgets/assetlist/partials/_body.htm b/plugins/indikator/devtools/widgets/assetlist/partials/_body.htm new file mode 100644 index 0000000..75dfc38 --- /dev/null +++ b/plugins/indikator/devtools/widgets/assetlist/partials/_body.htm @@ -0,0 +1,8 @@ +makePartial('toolbar') ?> +
    +
    +
    + makePartial('files', ['data'=>$data]) ?> +
    +
    +
    diff --git a/plugins/indikator/devtools/widgets/assetlist/partials/_files.htm b/plugins/indikator/devtools/widgets/assetlist/partials/_files.htm new file mode 100644 index 0000000..8b57fbd --- /dev/null +++ b/plugins/indikator/devtools/widgets/assetlist/partials/_files.htm @@ -0,0 +1,7 @@ +
    +
    +
    + makePartial('items', ['items'=>$data]) ?> +
    +
    +
    diff --git a/plugins/indikator/devtools/widgets/assetlist/partials/_items.htm b/plugins/indikator/devtools/widgets/assetlist/partials/_items.htm new file mode 100644 index 0000000..1a378e1 --- /dev/null +++ b/plugins/indikator/devtools/widgets/assetlist/partials/_items.htm @@ -0,0 +1,57 @@ +isSearchMode(); + + if (($upPath = $this->getUpPath()) !== null && !$searchMode): +?> +

    + getCurrentRelativePath() ?> +

    + +
    + +
      + path, '/'); + ?> +
    • editable): ?>data-editable data-item-path="path, '/')) ?>" data-item-type="asset" data-id=""> + + name) ?> + + + + path)) ?> + + + + +
      + +
      + + +
      + path) ?> + isItemSelected($item->path) ? 'checked' : null ?> + data-request="getEventHandler('onSelect') ?>" + value="1"> + +
      + +
    • + +
    + +

    noRecordsMessage)) ?>

    + +
    diff --git a/plugins/indikator/devtools/widgets/assetlist/partials/_move_form.htm b/plugins/indikator/devtools/widgets/assetlist/partials/_move_form.htm new file mode 100644 index 0000000..1cec459 --- /dev/null +++ b/plugins/indikator/devtools/widgets/assetlist/partials/_move_form.htm @@ -0,0 +1,40 @@ +$this->getEventHandler('onMove'), + 'data-request-success'=>"\$(this).trigger('close.oc.popup')", + 'data-stripe-load-indicator'=>1, + 'id'=>'asset-move-popup-form' +]) ?> + + + + diff --git a/plugins/indikator/devtools/widgets/assetlist/partials/_new_dir_form.htm b/plugins/indikator/devtools/widgets/assetlist/partials/_new_dir_form.htm new file mode 100644 index 0000000..eb5b2ad --- /dev/null +++ b/plugins/indikator/devtools/widgets/assetlist/partials/_new_dir_form.htm @@ -0,0 +1,45 @@ +$this->getEventHandler('onNewDirectory'), + 'data-request-success'=>"\$(this).trigger('close.oc.popup')", + 'data-stripe-load-indicator'=>1, + 'id'=>'asset-new-dir-popup-form' +]) ?> + + + + + + + + diff --git a/plugins/indikator/devtools/widgets/assetlist/partials/_rename_form.htm b/plugins/indikator/devtools/widgets/assetlist/partials/_rename_form.htm new file mode 100644 index 0000000..29221a0 --- /dev/null +++ b/plugins/indikator/devtools/widgets/assetlist/partials/_rename_form.htm @@ -0,0 +1,46 @@ +getEventHandler('onApplyName'), [ + 'success' => "\$el.trigger('close.oc.popup');", + 'data-stripe-load-indicator' => 1, + 'id' => 'asset-rename-popup-form' +]) ?> + + + + + + + + diff --git a/plugins/indikator/devtools/widgets/assetlist/partials/_toolbar.htm b/plugins/indikator/devtools/widgets/assetlist/partials/_toolbar.htm new file mode 100644 index 0000000..7764cc0 --- /dev/null +++ b/plugins/indikator/devtools/widgets/assetlist/partials/_toolbar.htm @@ -0,0 +1,77 @@ +
    +
    + + +
    +
    + + + +
    +
    + + +
    + +
    + +
    +
    diff --git a/plugins/romanah/bagisto/Plugin.php b/plugins/romanah/bagisto/Plugin.php index 4222c8f..a57f488 100755 --- a/plugins/romanah/bagisto/Plugin.php +++ b/plugins/romanah/bagisto/Plugin.php @@ -26,6 +26,9 @@ class Plugin extends PluginBase */ public function registerComponents() { + return [ + 'Romanah\Bagisto\Components\Products' => 'products' + ]; } /** diff --git a/plugins/romanah/bagisto/components/Products.php b/plugins/romanah/bagisto/components/Products.php new file mode 100644 index 0000000..5ca6b4f --- /dev/null +++ b/plugins/romanah/bagisto/components/Products.php @@ -0,0 +1,32 @@ + 'Products', + 'description' => 'Fetch Products settings' + ]; + } + + public $bagisto_url = 'https://nurgul.com.tm/app/api/'; + + public function onFetchProduct() + { + $response = Http::get('https://nurgul.com.tm/app/api/products?locale=tm&limit=4'); + // $response = getenv('APP_URL'); + // dd($response); + return $response; + } + + +} diff --git a/plugins/romanah/bagisto/controllers/Brand.php b/plugins/romanah/bagisto/controllers/Brand.php new file mode 100755 index 0000000..b74ecd9 --- /dev/null +++ b/plugins/romanah/bagisto/controllers/Brand.php @@ -0,0 +1,18 @@ + + + +
    diff --git a/plugins/romanah/bagisto/controllers/brand/config_form.yaml b/plugins/romanah/bagisto/controllers/brand/config_form.yaml new file mode 100755 index 0000000..bf2462f --- /dev/null +++ b/plugins/romanah/bagisto/controllers/brand/config_form.yaml @@ -0,0 +1,10 @@ +name: Brand +form: $/romanah/bagisto/models/brand/fields.yaml +modelClass: Romanah\Bagisto\Models\Brand +defaultRedirect: romanah/bagisto/brand +create: + redirect: 'romanah/bagisto/brand/update/:id' + redirectClose: romanah/bagisto/brand +update: + redirect: romanah/bagisto/brand + redirectClose: romanah/bagisto/brand diff --git a/plugins/romanah/bagisto/controllers/brand/config_list.yaml b/plugins/romanah/bagisto/controllers/brand/config_list.yaml new file mode 100755 index 0000000..5f8a3c8 --- /dev/null +++ b/plugins/romanah/bagisto/controllers/brand/config_list.yaml @@ -0,0 +1,12 @@ +list: $/romanah/bagisto/models/brand/columns.yaml +modelClass: Romanah\Bagisto\Models\Brand +title: Brand +noRecordsMessage: 'backend::lang.list.no_records' +showSetup: true +showCheckboxes: true +recordsPerPage: 20 +toolbar: + buttons: list_toolbar + search: + prompt: 'backend::lang.list.search_prompt' +recordUrl: 'romanah/bagisto/brand/update/:id' diff --git a/plugins/romanah/bagisto/controllers/brand/create.htm b/plugins/romanah/bagisto/controllers/brand/create.htm new file mode 100755 index 0000000..a38c92b --- /dev/null +++ b/plugins/romanah/bagisto/controllers/brand/create.htm @@ -0,0 +1,46 @@ + +
      +
    • Brand
    • +
    • pageTitle) ?>
    • +
    + + +fatalError): ?> + + 'layout']) ?> + +
    + formRender() ?> +
    + +
    +
    + + + + + +
    +
    + + + + +

    fatalError)) ?>

    +

    + \ No newline at end of file diff --git a/plugins/romanah/bagisto/controllers/brand/index.htm b/plugins/romanah/bagisto/controllers/brand/index.htm new file mode 100755 index 0000000..ea43a36 --- /dev/null +++ b/plugins/romanah/bagisto/controllers/brand/index.htm @@ -0,0 +1 @@ +listRender() ?> diff --git a/plugins/romanah/bagisto/controllers/brand/preview.htm b/plugins/romanah/bagisto/controllers/brand/preview.htm new file mode 100755 index 0000000..7109b5b --- /dev/null +++ b/plugins/romanah/bagisto/controllers/brand/preview.htm @@ -0,0 +1,22 @@ + +
      +
    • Brand
    • +
    • pageTitle) ?>
    • +
    + + +fatalError): ?> + +
    + formRenderPreview() ?> +
    + + +

    fatalError) ?>

    + + +

    + + + +

    \ No newline at end of file diff --git a/plugins/romanah/bagisto/controllers/brand/update.htm b/plugins/romanah/bagisto/controllers/brand/update.htm new file mode 100755 index 0000000..1e3a108 --- /dev/null +++ b/plugins/romanah/bagisto/controllers/brand/update.htm @@ -0,0 +1,54 @@ + +
      +
    • Brand
    • +
    • pageTitle) ?>
    • +
    + + +fatalError): ?> + + 'layout']) ?> + +
    + formRender() ?> +
    + +
    +
    + + + + + + + +
    +
    + + + +

    fatalError)) ?>

    +

    + \ No newline at end of file diff --git a/plugins/romanah/bagisto/controllers/slider/_list_toolbar.htm b/plugins/romanah/bagisto/controllers/slider/_list_toolbar.htm new file mode 100755 index 0000000..c02137f --- /dev/null +++ b/plugins/romanah/bagisto/controllers/slider/_list_toolbar.htm @@ -0,0 +1,18 @@ +
    + + +
    diff --git a/plugins/romanah/bagisto/controllers/slider/config_form.yaml b/plugins/romanah/bagisto/controllers/slider/config_form.yaml new file mode 100755 index 0000000..5da39b0 --- /dev/null +++ b/plugins/romanah/bagisto/controllers/slider/config_form.yaml @@ -0,0 +1,10 @@ +name: Slider +form: $/romanah/bagisto/models/slider/fields.yaml +modelClass: Romanah\Bagisto\Models\Slider +defaultRedirect: romanah/bagisto/slider +create: + redirect: 'romanah/bagisto/slider/update/:id' + redirectClose: romanah/bagisto/slider +update: + redirect: romanah/bagisto/slider + redirectClose: romanah/bagisto/slider diff --git a/plugins/romanah/bagisto/controllers/slider/config_list.yaml b/plugins/romanah/bagisto/controllers/slider/config_list.yaml new file mode 100755 index 0000000..ff91715 --- /dev/null +++ b/plugins/romanah/bagisto/controllers/slider/config_list.yaml @@ -0,0 +1,12 @@ +list: $/romanah/bagisto/models/slider/columns.yaml +modelClass: Romanah\Bagisto\Models\Slider +title: Slider +noRecordsMessage: 'backend::lang.list.no_records' +showSetup: true +showCheckboxes: true +recordsPerPage: 20 +toolbar: + buttons: list_toolbar + search: + prompt: 'backend::lang.list.search_prompt' +recordUrl: 'romanah/bagisto/slider/update/:id' diff --git a/plugins/romanah/bagisto/controllers/slider/create.htm b/plugins/romanah/bagisto/controllers/slider/create.htm new file mode 100755 index 0000000..abd235b --- /dev/null +++ b/plugins/romanah/bagisto/controllers/slider/create.htm @@ -0,0 +1,46 @@ + + + + +fatalError): ?> + + 'layout']) ?> + +
    + formRender() ?> +
    + +
    +
    + + + + + +
    +
    + + + + +

    fatalError)) ?>

    +

    + \ No newline at end of file diff --git a/plugins/romanah/bagisto/controllers/slider/index.htm b/plugins/romanah/bagisto/controllers/slider/index.htm new file mode 100755 index 0000000..ea43a36 --- /dev/null +++ b/plugins/romanah/bagisto/controllers/slider/index.htm @@ -0,0 +1 @@ +listRender() ?> diff --git a/plugins/romanah/bagisto/controllers/slider/preview.htm b/plugins/romanah/bagisto/controllers/slider/preview.htm new file mode 100755 index 0000000..a9388de --- /dev/null +++ b/plugins/romanah/bagisto/controllers/slider/preview.htm @@ -0,0 +1,22 @@ + + + + +fatalError): ?> + +
    + formRenderPreview() ?> +
    + + +

    fatalError) ?>

    + + +

    + + + +

    \ No newline at end of file diff --git a/plugins/romanah/bagisto/controllers/slider/update.htm b/plugins/romanah/bagisto/controllers/slider/update.htm new file mode 100755 index 0000000..2f65dd1 --- /dev/null +++ b/plugins/romanah/bagisto/controllers/slider/update.htm @@ -0,0 +1,54 @@ + + + + +fatalError): ?> + + 'layout']) ?> + +
    + formRender() ?> +
    + +
    +
    + + + + + + + +
    +
    + + + +

    fatalError)) ?>

    +

    + \ No newline at end of file diff --git a/plugins/romanah/bagisto/models/Brand.php b/plugins/romanah/bagisto/models/Brand.php new file mode 100755 index 0000000..1c25184 --- /dev/null +++ b/plugins/romanah/bagisto/models/Brand.php @@ -0,0 +1,27 @@ +engine = 'InnoDB'; + $table->increments('id')->unsigned(); + $table->timestamp('created_at')->nullable(); + $table->timestamp('updated_at')->nullable(); + $table->timestamp('deleted_at')->nullable(); + $table->string('img')->nullable(); + $table->string('note')->nullable(); + }); + } + + public function down() + { + Schema::dropIfExists('romanah_bagisto_brand'); + } +} diff --git a/plugins/romanah/bagisto/updates/builder_table_create_romanah_bagisto_slider.php b/plugins/romanah/bagisto/updates/builder_table_create_romanah_bagisto_slider.php new file mode 100755 index 0000000..0487010 --- /dev/null +++ b/plugins/romanah/bagisto/updates/builder_table_create_romanah_bagisto_slider.php @@ -0,0 +1,30 @@ +engine = 'InnoDB'; + $table->increments('id')->unsigned(); + $table->timestamp('created_at')->nullable(); + $table->timestamp('updated_at')->nullable(); + $table->timestamp('deleted_at')->nullable(); + $table->string('img')->nullable(); + $table->string('header')->nullable(); + $table->string('header2')->nullable(); + $table->text('txt')->nullable(); + $table->string('btn_txt')->nullable(); + $table->string('url')->nullable(); + }); + } + + public function down() + { + Schema::dropIfExists('romanah_bagisto_slider'); + } +} diff --git a/plugins/romanah/bagisto/updates/version.yaml b/plugins/romanah/bagisto/updates/version.yaml index 5c3faad..06ec67b 100755 --- a/plugins/romanah/bagisto/updates/version.yaml +++ b/plugins/romanah/bagisto/updates/version.yaml @@ -1,2 +1,8 @@ -v1.0.1: +1.0.1: - 'Initialize plugin' +1.0.2: + - 'Created table romanah_bagisto_slider' + - builder_table_create_romanah_bagisto_slider.php +1.0.3: + - 'Created table romanah_bagisto_brand' + - builder_table_create_romanah_bagisto_brand.php diff --git a/themes/nurgul/assets/jquery.js b/themes/nurgul/assets/jquery.js new file mode 100644 index 0000000..c4c6022 --- /dev/null +++ b/themes/nurgul/assets/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.0 | (c) OpenJS 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(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),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("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(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 de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){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[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.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},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.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},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(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?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===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]||se.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]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(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(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
    ",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0 + + {% styles %} @@ -60,10 +62,15 @@ code = "top-menu" + + {% framework %} + + {% scripts %} %} + \ No newline at end of file diff --git a/themes/nurgul/pages/home.htm b/themes/nurgul/pages/home.htm index d06385b..c90b4cb 100755 --- a/themes/nurgul/pages/home.htm +++ b/themes/nurgul/pages/home.htm @@ -1,14 +1,15 @@ url = "/" layout = "main" title = "Home" -== +[products] +== {% partial 'home/slider' %} {% partial 'home/banner' %} {% partial 'home/banner2' %} - + {% partial 'home/new-products' header='New Products' %} {% partial 'home/banner-mix' %} @@ -23,7 +24,7 @@ title = "Home"
    - Banner Image + Nurgul
    @@ -33,4 +34,4 @@ title = "Home" -{% partial 'home/brand' %} +{% partial 'home/brand' %} \ No newline at end of file diff --git a/themes/nurgul/partials/footer.htm b/themes/nurgul/partials/footer.htm index 5050d4b..9d5d948 100755 --- a/themes/nurgul/partials/footer.htm +++ b/themes/nurgul/partials/footer.htm @@ -7,7 +7,7 @@
    @@ -15,20 +15,20 @@
    - + \ No newline at end of file diff --git a/themes/nurgul/partials/home/banner-mix.htm b/themes/nurgul/partials/home/banner-mix.htm index 04adf78..1c99d25 100755 --- a/themes/nurgul/partials/home/banner-mix.htm +++ b/themes/nurgul/partials/home/banner-mix.htm @@ -5,14 +5,14 @@
    - Banner Image + Nurgul
    - Banner Image + Nurgul
    diff --git a/themes/nurgul/partials/home/banner.htm b/themes/nurgul/partials/home/banner.htm index 6cf9286..60614d0 100755 --- a/themes/nurgul/partials/home/banner.htm +++ b/themes/nurgul/partials/home/banner.htm @@ -10,8 +10,8 @@ #
    -

    Free shipping

    -

    On all orders over $49.00

    +

    {{'home.free.shipping.title'|_}}

    +

    {{'home.free.shipping.txt'|_}}

    @@ -19,8 +19,8 @@ #
    -

    15 days returns

    -

    Moneyback guarantee

    +

    {{'home.title.second'|_}}

    +

    {{'home.desc.second'|_}}

    @@ -28,8 +28,8 @@ #
    -

    Secure checkout

    -

    Protected by Paypal

    +

    {{'home.title.third'|_}}

    +

    {{'home.desc.third'|_}}

    @@ -37,8 +37,8 @@ #
    -

    Offer & gift here

    -

    On all orders over

    +

    {{'home.title.fourth'|_}}

    +

    {{'home.desc.fourth'|_}}

    @@ -46,4 +46,4 @@ - + \ No newline at end of file diff --git a/themes/nurgul/partials/home/banner2.htm b/themes/nurgul/partials/home/banner2.htm index 77a3593..2c31cb1 100755 --- a/themes/nurgul/partials/home/banner2.htm +++ b/themes/nurgul/partials/home/banner2.htm @@ -5,25 +5,25 @@
    - Banner Image + Nurgul
    - Banner Image + Nurgul
    - Banner Image + Nurgul
    - + \ No newline at end of file diff --git a/themes/nurgul/partials/home/brand-item.htm b/themes/nurgul/partials/home/brand-item.htm index 0f98244..ad2ab52 100755 --- a/themes/nurgul/partials/home/brand-item.htm +++ b/themes/nurgul/partials/home/brand-item.htm @@ -1,5 +1,5 @@
    - Brand Logo + Brand Logo
    -
    + \ No newline at end of file diff --git a/themes/nurgul/partials/home/brand.htm b/themes/nurgul/partials/home/brand.htm index c8e0590..012f586 100755 --- a/themes/nurgul/partials/home/brand.htm +++ b/themes/nurgul/partials/home/brand.htm @@ -1,20 +1,31 @@ +[builderList] +modelClass = "Romanah\Bagisto\Models\Brand" +scope = "-" +scopeValue = "{{ :scope }}" +displayColumn = "id" +noRecordsMessage = "No records found" +detailsPage = "-" +detailsUrlParameter = "id" +pageNumber = "{{ :page }}" +== +{% set records = builderList.records %} +{% set displayColumn = builderList.displayColumn %} +{% set noRecordsMessage = builderList.noRecordsMessage %} +{% set detailsPage = builderList.detailsPage %} +{% set detailsKeyColumn = builderList.detailsKeyColumn %} +{% set detailsUrlParameter = builderList.detailsUrlParameter %} + +
    - {% partial "home/brand-item" %} - {% partial "home/brand-item" %} - {% partial "home/brand-item" %} - {% partial "home/brand-item" %} - {% partial "home/brand-item" %} - {% partial "home/brand-item" %} - {% partial "home/brand-item" %} - {% partial "home/brand-item" %} - {% partial "home/brand-item" %} - {% partial "home/brand-item" %} + {% for record in records %} + {% partial "home/brand-item" img=record.img %} + {% endfor %}
    - + \ No newline at end of file diff --git a/themes/nurgul/partials/home/slider.htm b/themes/nurgul/partials/home/slider.htm index 69f5dc7..8c58910 100755 --- a/themes/nurgul/partials/home/slider.htm +++ b/themes/nurgul/partials/home/slider.htm @@ -1,77 +1,63 @@ +[builderList] +modelClass = "Romanah\Bagisto\Models\Slider" +scope = "-" +scopeValue = "{{ :scope }}" +displayColumn = "id" +noRecordsMessage = "No records found" +detailsPage = "-" +detailsUrlParameter = "id" +pageNumber = "{{ :page }}" +== +{% set records = builderList.records %} +{% set displayColumn = builderList.displayColumn %} +{% set noRecordsMessage = builderList.noRecordsMessage %} +{% set detailsPage = builderList.detailsPage %} +{% set detailsKeyColumn = builderList.detailsKeyColumn %} +{% set detailsUrlParameter = builderList.detailsUrlParameter %} +
    - -
    -
    -
    -
    -
    -
    -
    -
    -
    -

    {{'Fresh Flower'|_}}

    -
    - Natural & Beautiful Flower Here
    -
    -

    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed - do eiusmod tempor incididunt ut labore.

    -
    -
    - Shop Now + + {% for record in records %} + +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    {{record.header}}

    +
    + {{record.header2}}
    +
    +

    {{record.txt}}

    +
    + +
    +
    +
    -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    -
    -
    -
    -

    Fresh Flower

    -
    - Natural & Beautiful Flower Here
    -
    -

    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed - do eiusmod tempor incididunt ut labore.

    -
    -
    - Shop Now -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
    - + + {% endfor %} + +
    \ No newline at end of file