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($('