feat: VivesPOS landing on Winter CMS 1.2 — theme + plugin + Dockerfile
Some checks are pending
Module sub-split / Sub-split (push) Waiting to run
Some checks are pending
Module sub-split / Sub-split (push) Waiting to run
- Base: wintercms/winter branch 1.2 (full framework) - Theme vivespos: Canvas 7 + Bootstrap 5 CDN, custom CSS - Layout: deferred GTM/GA4 tracking, JSON-LD SoftwareApplication - Partials: hero (offline-first), features, modes (offline/nube toggle), screenshots, pricing (3 planes), comparison, FAQ, CTA - Plugin VivesPOS.Site with ContactForm - Dockerfile: PHP 8.2 Apache, port 80, healthcheck - Added winter/wn-pages, blog, sitemap, seo plugins - Active theme set to vivespos
This commit is contained in:
113
modules/cms/assets/js/themelogs/template-diff.js
Normal file
113
modules/cms/assets/js/themelogs/template-diff.js
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Template Diff plugin
|
||||
*
|
||||
* Data attributes:
|
||||
* - data-plugin="template-diff" - enables the plugin on an element
|
||||
*
|
||||
* JavaScript API:
|
||||
* $('pre').templateDiff({ option: 'value' })
|
||||
*
|
||||
* Dependences:
|
||||
* - jsdiff (diff.js)
|
||||
*/
|
||||
|
||||
+function ($) { "use strict";
|
||||
|
||||
// TEMPALTE DIFF CLASS DEFINITION
|
||||
// ============================
|
||||
|
||||
var TemplateDiff = function(element, options) {
|
||||
this.options = options
|
||||
this.$el = $(element)
|
||||
|
||||
// Init
|
||||
this.init()
|
||||
}
|
||||
|
||||
TemplateDiff.DEFAULTS = {
|
||||
oldFieldName: null,
|
||||
newFieldName: null,
|
||||
contentTag: '',
|
||||
diffType: 'lines' // chars, words, lines
|
||||
}
|
||||
|
||||
TemplateDiff.prototype.init = function() {
|
||||
var
|
||||
oldValue = $('[data-field-name="'+this.options.oldFieldName+'"] .form-control '+this.options.contentTag).html(),
|
||||
newValue = $('[data-field-name="'+this.options.newFieldName+'"] .form-control '+this.options.contentTag).html()
|
||||
|
||||
oldValue = $('<div />').html(oldValue).text()
|
||||
newValue = $('<div />').html(newValue).text()
|
||||
|
||||
this.diffStrings(oldValue, newValue)
|
||||
}
|
||||
|
||||
TemplateDiff.prototype.diffStrings = function(oldValue, newValue) {
|
||||
var result = this.$el.get(0)
|
||||
var diffType = 'diff' + this.options.diffType[0].toUpperCase() + this.options.diffType.slice(1)
|
||||
var diff = JsDiff[diffType](oldValue, newValue)
|
||||
var fragment = document.createDocumentFragment();
|
||||
for (var i=0; i < diff.length; i++) {
|
||||
|
||||
if (diff[i].added && diff[i + 1] && diff[i + 1].removed) {
|
||||
var swap = diff[i];
|
||||
diff[i] = diff[i + 1];
|
||||
diff[i + 1] = swap;
|
||||
}
|
||||
|
||||
var node;
|
||||
if (diff[i].removed) {
|
||||
node = document.createElement('del');
|
||||
node.appendChild(document.createTextNode(diff[i].value));
|
||||
}
|
||||
else if (diff[i].added) {
|
||||
node = document.createElement('ins');
|
||||
node.appendChild(document.createTextNode(diff[i].value));
|
||||
}
|
||||
else {
|
||||
node = document.createTextNode(diff[i].value);
|
||||
}
|
||||
fragment.appendChild(node);
|
||||
}
|
||||
|
||||
result.textContent = '';
|
||||
result.appendChild(fragment);
|
||||
}
|
||||
|
||||
// TEMPALTE DIFF PLUGIN DEFINITION
|
||||
// ============================
|
||||
|
||||
var old = $.fn.templateDiff
|
||||
|
||||
$.fn.templateDiff = function (option) {
|
||||
var args = Array.prototype.slice.call(arguments, 1), result
|
||||
this.each(function () {
|
||||
var $this = $(this)
|
||||
var data = $this.data('oc.example')
|
||||
var options = $.extend({}, TemplateDiff.DEFAULTS, $this.data(), typeof option == 'object' && option)
|
||||
if (!data) $this.data('oc.example', (data = new TemplateDiff(this, options)))
|
||||
if (typeof option == 'string') result = data[option].apply(data, args)
|
||||
if (typeof result != 'undefined') return false
|
||||
})
|
||||
|
||||
return result ? result : this
|
||||
}
|
||||
|
||||
$.fn.templateDiff.Constructor = TemplateDiff
|
||||
|
||||
// TEMPALTE DIFF NO CONFLICT
|
||||
// =================
|
||||
|
||||
$.fn.templateDiff.noConflict = function () {
|
||||
$.fn.templateDiff = old
|
||||
return this
|
||||
}
|
||||
|
||||
// TEMPALTE DIFF DATA-API
|
||||
// ===============
|
||||
|
||||
$(document).render(function () {
|
||||
$('[data-plugin="template-diff"]').templateDiff()
|
||||
});
|
||||
|
||||
}(window.jQuery);
|
||||
701
modules/cms/assets/js/winter.cmspage.js
Normal file
701
modules/cms/assets/js/winter.cmspage.js
Normal file
@@ -0,0 +1,701 @@
|
||||
/*
|
||||
* Scripts for the CMS page.
|
||||
*/
|
||||
+function ($) { "use strict";
|
||||
|
||||
var Base = $.wn.foundation.base,
|
||||
BaseProto = Base.prototype
|
||||
|
||||
var CmsPage = function() {
|
||||
|
||||
Base.call(this)
|
||||
|
||||
//
|
||||
// Initialization
|
||||
//
|
||||
|
||||
this.init()
|
||||
this.widgets = Snowboard['backend.ui.widgetHandler']()
|
||||
}
|
||||
|
||||
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))
|
||||
|
||||
// Watch for PHP editors
|
||||
window.Snowboard.on('backend.formwidget.codeeditor.create', this.proxy(this.onCodeEditorCreate));
|
||||
}
|
||||
|
||||
// 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
|
||||
*/
|
||||
$.wn.stripeLoadIndicator.show()
|
||||
|
||||
$form.request('onOpenTemplate', {
|
||||
data: data
|
||||
}).done(function(data) {
|
||||
$.wn.stripeLoadIndicator.hide()
|
||||
$('#cms-master-tabs').ocTab('addTab', data.tabTitle, data.tab, tabId, $form.data('type-icon'))
|
||||
}).always(function() {
|
||||
$.wn.stripeLoadIndicator.hide()
|
||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||
$.wn.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')
|
||||
|
||||
$.wn.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 = $('<a href="javascript:;" class="tab-collapse-icon tabless"><i class="icon-chevron-up"></i></a>'),
|
||||
$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 = $('<a href="javascript:;" class="tab-collapse-icon primary"><i class="icon-chevron-down"></i></a>'),
|
||||
$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)
|
||||
|
||||
var $form = $('form', data.pane),
|
||||
self = this
|
||||
|
||||
$form.on('changed.oc.changeMonitor', function() {
|
||||
$panel.trigger('modified.oc.tab')
|
||||
$panel.find('[data-control=commit-button]').addClass('hide');
|
||||
$panel.find('[data-control=reset-button]').addClass('hide');
|
||||
self.updateModifiedCounter()
|
||||
})
|
||||
|
||||
$form.on('unchanged.oc.changeMonitor', function() {
|
||||
$panel.trigger('unmodified.oc.tab')
|
||||
self.updateModifiedCounter()
|
||||
})
|
||||
}
|
||||
|
||||
CmsPage.prototype.onCodeEditorCreate = function (widget, editor) {
|
||||
const $form = $(widget.element.closest('form'));
|
||||
|
||||
if (widget.config.get('language') === 'php') {
|
||||
let value = widget.getValue();
|
||||
|
||||
// If no PHP tag at the start, prepend one
|
||||
if (!/^<\?php\s*/.test(value)) {
|
||||
widget.setValue('<?php\n' + value);
|
||||
}
|
||||
|
||||
// Verify the editor has at least 2 lines before hiding line 1
|
||||
const lineCount = widget.getModel().getLineCount();
|
||||
if (lineCount >= 2) {
|
||||
// Only hide line 1 if it contains just the PHP open tag
|
||||
const firstLine = widget.getModel().getLineContent(1);
|
||||
if (/^<\?php\s*$/.test(firstLine)) {
|
||||
widget.fromLine(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add codelens and action to customise component templates
|
||||
const templateCommand = editor.addCommand(
|
||||
0,
|
||||
function (command, range, name) {
|
||||
$form.request('onExpandMarkupToken', {
|
||||
data: {
|
||||
tokenType: 'component',
|
||||
tokenName: name,
|
||||
},
|
||||
success: function (data) {
|
||||
if (data.result) {
|
||||
widget.replace(range, data.result)
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
widget.addCodeLens(
|
||||
'twig',
|
||||
function (model, token) {
|
||||
// Find component tags
|
||||
const lenses = [];
|
||||
const matches = model.findMatches('\\{%\\scomponent\\s[\'"]([^\'"]+)[\'"][^%]*\\s%\\}', true, true, false, null, true);
|
||||
|
||||
matches.forEach((match) => {
|
||||
const name = match.matches[1] ?? 'unknown';
|
||||
lenses.push({
|
||||
range: match.range,
|
||||
id: 'component-' + name + '-lens',
|
||||
command: {
|
||||
title: 'Customize template',
|
||||
id: templateCommand,
|
||||
arguments: [match.range, name]
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
lenses: lenses,
|
||||
dispose: function () {
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
// Update the visibilities of the commit & reset buttons
|
||||
$('[data-control=commit-button]', element).toggleClass('hide', !data.canCommit)
|
||||
$('[data-control=reset-button]', element).toggleClass('hide', !data.canReset)
|
||||
|
||||
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) {
|
||||
$.wn.cmsPage.updateTemplateList(templateType)
|
||||
|
||||
if (templateType == 'layout')
|
||||
this.updateLayouts(element)
|
||||
}
|
||||
|
||||
if (context.handler == 'onSave' && (!data['X_WINTER_ERROR_FIELDS'] && !data['X_WINTER_ERROR_MESSAGE'])) {
|
||||
$(element).trigger('unchange.oc.changeMonitor')
|
||||
}
|
||||
|
||||
// Reload the form if the server has requested it
|
||||
if (data.forceReload) {
|
||||
this.reloadForm(element)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
$.wn.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(){
|
||||
$.wn.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
|
||||
|
||||
$.wn.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)
|
||||
$.wn.flashMsg({text: data.error, 'class': 'error'})
|
||||
}).always(function(){
|
||||
self.updateTemplateList(templateType)
|
||||
$.wn.stripeLoadIndicator.hide()
|
||||
})
|
||||
}
|
||||
|
||||
CmsPage.prototype.onInspectorShowing = function(ev, data) {
|
||||
var $dragScroll = $(ev.currentTarget).closest('[data-control="toolbar"]').data('oc.dragScroll')
|
||||
if ($dragScroll) {
|
||||
$dragScroll.goToElement(ev.currentTarget, data.callback)
|
||||
} else {
|
||||
data.callback();
|
||||
}
|
||||
|
||||
ev.stopPropagation()
|
||||
}
|
||||
|
||||
CmsPage.prototype.onInspectorHidden = function(ev) {
|
||||
var element = ev.target,
|
||||
values = JSON.parse($('[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 = JSON.parse($('[data-inspector-values]', element).val()),
|
||||
alias = values['oc.alias'],
|
||||
$componentList = $('#cms-master-tabs > div.tab-content > .tab-pane.active .control-componentlist .layout'),
|
||||
$cell = $(ev.target).parent()
|
||||
|
||||
$('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().replace(/^@/, ''),
|
||||
codeEditor = this.widgets.getWidget(editor.get(0))
|
||||
|
||||
codeEditor.replace(new RegExp('\\{% +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.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){
|
||||
$.wn.sideNav.setCounter('cms/' + data.menu, data.count);
|
||||
})
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
$.wn.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() {
|
||||
$.wn.stripeLoadIndicator.hide()
|
||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||
alert(jqXHR.responseText.length ? jqXHR.responseText : jqXHR.statusText)
|
||||
})
|
||||
}
|
||||
|
||||
CmsPage.prototype.setPageTitle = function(title) {
|
||||
if (title.length)
|
||||
$.wn.layout.setPageTitle(title + ' | ')
|
||||
else
|
||||
$.wn.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($('<option>').attr('value', layoutFile).text(layoutName))
|
||||
})
|
||||
$select.trigger('pause.oc.changeMonitor')
|
||||
$select.val(value)
|
||||
$select.trigger('change')
|
||||
$select.trigger('resume.oc.changeMonitor')
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
$.wn.cmsPage = new CmsPage();
|
||||
}(window.jQuery);
|
||||
260
modules/cms/assets/js/winter.dragcomponents.js
Normal file
260
modules/cms/assets/js/winter.dragcomponents.js
Normal file
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* DragComponents plugin
|
||||
*
|
||||
* Data attributes:
|
||||
* - data-control="dragcomponents" - enables the plugin on an element
|
||||
* - data-option="value" - an option with a value
|
||||
*
|
||||
* JavaScript API:
|
||||
* $('a#someElement').dragComponents({ option: 'value' })
|
||||
*
|
||||
* Dependences:
|
||||
* - Some other plugin (filename.js)
|
||||
*/
|
||||
|
||||
+function ($) { "use strict";
|
||||
|
||||
// DRAGCOMPONENTS CLASS DEFINITION
|
||||
// ============================
|
||||
|
||||
var DragComponents = function(element, options) {
|
||||
var self = this
|
||||
this.options = options
|
||||
this.$el = $(element)
|
||||
|
||||
var $el = this.$el,
|
||||
widgets = Snowboard['backend.ui.widgetHandler'](),
|
||||
$clone,
|
||||
$editorArea,
|
||||
$editor,
|
||||
$componentList,
|
||||
adjX = 0,
|
||||
adjY = 0,
|
||||
dragging = false,
|
||||
startPos,
|
||||
editorPos
|
||||
|
||||
$el.mousedown(function(event){
|
||||
if ($el.data('component-attached')) return
|
||||
|
||||
startDrag(event)
|
||||
return false
|
||||
})
|
||||
|
||||
$el.on('touchstart', function(event){
|
||||
if ($el.data('component-attached')) return
|
||||
|
||||
var touchEvent = event.originalEvent;
|
||||
if (touchEvent.touches.length == 1) {
|
||||
startDrag(touchEvent.touches[0])
|
||||
event.stopPropagation()
|
||||
}
|
||||
})
|
||||
|
||||
function initDrag(event) {
|
||||
$componentList = $('#cms-master-tabs > div.tab-content > .tab-pane.active .control-componentlist')
|
||||
$el.addClass(self.options.placeholderClass)
|
||||
$clone.show()
|
||||
$editorArea = $('#cms-master-tabs > div.tab-content > .tab-pane.active [data-control="codeeditor"]')
|
||||
if (!$editorArea.length) {
|
||||
return
|
||||
}
|
||||
|
||||
$editor = widgets.getWidget($editorArea.get(0));
|
||||
if (!$editor || !$editor.getEditor()) return;
|
||||
$editor.getEditor().focus();
|
||||
editorPos = $editor.getEditor().onMouseMove((event) => {
|
||||
if (event.target && event.target.position) {
|
||||
$editor.getEditor().setPosition(event.target.position);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal event, drag has started
|
||||
*/
|
||||
function startDrag(event) {
|
||||
|
||||
startPos = $el.offset()
|
||||
$clone = $el.clone().appendTo($(document.body))
|
||||
|
||||
$clone
|
||||
.css({
|
||||
zIndex: '99999',
|
||||
position: 'absolute',
|
||||
pointerEvents: 'none'
|
||||
})
|
||||
.addClass('draggable-component-item')
|
||||
.width($el.width())
|
||||
.height($el.height())
|
||||
.hide()
|
||||
|
||||
var objX = (event.pageX - startPos.left),
|
||||
objY = (event.pageY - startPos.top)
|
||||
|
||||
$clone.data('dragComponents', { x: objX, y: objY })
|
||||
|
||||
if (Modernizr.touchevents) {
|
||||
$(window).on('touchmove.oc.dragcomponents', function(event){
|
||||
var touchEvent = event.originalEvent
|
||||
moveDrag(touchEvent.touches[0])
|
||||
event.preventDefault()
|
||||
})
|
||||
|
||||
$(window).on('touchend.oc.dragcomponents', function(event) {
|
||||
stopDrag()
|
||||
})
|
||||
}
|
||||
else {
|
||||
$(window).on('mousemove.oc.dragcomponents', function(event){
|
||||
moveDrag(event)
|
||||
$(document.body).addClass(self.options.dragClass)
|
||||
return false
|
||||
})
|
||||
|
||||
$(window).on('mouseup.oc.dragcomponents', function(mouseUpEvent){
|
||||
var isClick = event.pageX == mouseUpEvent.pageX && event.pageY == mouseUpEvent.pageY
|
||||
stopDrag(isClick)
|
||||
return false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal event, drag is active
|
||||
*/
|
||||
function moveDrag(event) {
|
||||
if (!dragging) {
|
||||
dragging = true
|
||||
initDrag(event)
|
||||
}
|
||||
|
||||
adjY = $(window).scrollTop()
|
||||
adjX = $(window).scrollLeft()
|
||||
var offset = $clone.data('dragComponents')
|
||||
$clone.css({
|
||||
left: (event.pageX - adjX - offset.x),
|
||||
top: (event.pageY - adjY - offset.y)
|
||||
})
|
||||
|
||||
if (collision($clone, $componentList))
|
||||
$componentList.addClass('droppable')
|
||||
else
|
||||
$componentList.removeClass('droppable')
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal event, drag has ended
|
||||
*/
|
||||
function stopDrag(click) {
|
||||
dragging = false
|
||||
|
||||
if (click)
|
||||
$(document.body).removeClass(self.options.dragClass)
|
||||
|
||||
$el.removeClass(self.options.placeholderClass)
|
||||
$(window)
|
||||
.off('mousemove.oc.dragcomponents mouseup.oc.dragcomponents')
|
||||
.removeData('dragComponents')
|
||||
|
||||
if (!click)
|
||||
finishDrag()
|
||||
|
||||
$clone.remove()
|
||||
|
||||
window.setTimeout(function(){
|
||||
if (!click) {
|
||||
$(document.body).removeClass(self.options.dragClass)
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
|
||||
function finishDrag() {
|
||||
// Dragged to the code editor
|
||||
if (collision($clone, $editorArea)) {
|
||||
// Add the component to the page
|
||||
$el.click()
|
||||
|
||||
// Can only attach to page or layouts
|
||||
if ($componentList.length && $editor && $editor.getEditor()) {
|
||||
// Inject {% component %} tag
|
||||
var alias = $('input[name="component_aliases[]"]', $el).val()
|
||||
$editor.insert("{% component '" + alias + "' %}")
|
||||
}
|
||||
}
|
||||
// Dragged to the component list
|
||||
else if (collision($clone, $componentList)) {
|
||||
// Add the component to the page
|
||||
$el.click()
|
||||
}
|
||||
|
||||
if (editorPos) {
|
||||
editorPos.dispose();
|
||||
}
|
||||
|
||||
if ($componentList.length) {
|
||||
$componentList.removeClass('droppable')
|
||||
}
|
||||
}
|
||||
|
||||
function collision($div1, $div2) {
|
||||
if (!$div1 || !$div2 || !$div1.length || !$div2.length)
|
||||
return false
|
||||
|
||||
var x1 = $div1.offset().left,
|
||||
y1 = $div1.offset().top,
|
||||
h1 = $div1.outerHeight(true),
|
||||
w1 = $div1.outerWidth(true),
|
||||
b1 = y1 + h1,
|
||||
r1 = x1 + w1,
|
||||
x2 = $div2.offset().left,
|
||||
y2 = $div2.offset().top,
|
||||
h2 = $div2.outerHeight(true),
|
||||
w2 = $div2.outerWidth(true),
|
||||
b2 = y2 + h2,
|
||||
r2 = x2 + w2
|
||||
|
||||
return !(b1 < y2 || y1 > b2 || r1 < x2 || x1 > r2)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DragComponents.DEFAULTS = {
|
||||
dragClass: 'drag',
|
||||
placeholderClass: 'placeholder'
|
||||
}
|
||||
|
||||
// DRAGCOMPONENTS PLUGIN DEFINITION
|
||||
// ============================
|
||||
|
||||
var old = $.fn.dragComponents
|
||||
|
||||
$.fn.dragComponents = function (option) {
|
||||
var args = Array.prototype.slice.call(arguments, 1)
|
||||
return this.each(function () {
|
||||
var $this = $(this)
|
||||
var data = $this.data('oc.dragcomponents')
|
||||
var options = $.extend({}, DragComponents.DEFAULTS, $this.data(), typeof option == 'object' && option)
|
||||
if (!data) $this.data('oc.dragcomponents', (data = new DragComponents(this, options)))
|
||||
else if (typeof option == 'string') data[option].apply(data, args)
|
||||
})
|
||||
}
|
||||
|
||||
$.fn.dragComponents.Constructor = DragComponents
|
||||
|
||||
// DRAGCOMPONENTS NO CONFLICT
|
||||
// =================
|
||||
|
||||
$.fn.dragComponents.noConflict = function () {
|
||||
$.fn.dragComponents = old
|
||||
return this
|
||||
}
|
||||
|
||||
// DRAGCOMPONENTS DATA-API
|
||||
// ===============
|
||||
|
||||
$(document).on('mouseenter.oc.dragcomponents', '[data-control="dragcomponent"]', function() {
|
||||
$(this).dragComponents()
|
||||
});
|
||||
|
||||
}(window.jQuery);
|
||||
183
modules/cms/assets/js/winter.tokenexpander.js
Normal file
183
modules/cms/assets/js/winter.tokenexpander.js
Normal file
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Token Expander plugin
|
||||
* Locates Twig tokens and replaces them with potential content inside.
|
||||
*
|
||||
* JavaScript API:
|
||||
* $('#codeEditor').tokenExpander({ option: 'value' })
|
||||
*
|
||||
* Dependences:
|
||||
* - Code Edtior (codeeditor.js)
|
||||
*/
|
||||
|
||||
+function ($) { "use strict";
|
||||
|
||||
// TOKEN EXPANDER CLASS DEFINITION
|
||||
// ============================
|
||||
|
||||
var TokenExpander = function(element, options) {
|
||||
this.options = options
|
||||
this.$el = $(element)
|
||||
|
||||
// Public properties
|
||||
this.something = false
|
||||
|
||||
// Init
|
||||
this.init()
|
||||
}
|
||||
|
||||
TokenExpander.DEFAULTS = {
|
||||
option: 'default'
|
||||
}
|
||||
|
||||
TokenExpander.prototype.init = function() {
|
||||
|
||||
this.$editor = this.$el.codeEditor('getEditorObject')
|
||||
this.$selection = this.$editor.getSelection()
|
||||
this.$session = this.$editor.getSession()
|
||||
this.tokenName = null
|
||||
this.tokenValue = null
|
||||
this.tokenDefinition = null
|
||||
this.tokenRange = null
|
||||
|
||||
this.$selection.on('changeCursor', $.proxy(this.cursorChange, this))
|
||||
}
|
||||
|
||||
TokenExpander.prototype.cursorChange = function(event) {
|
||||
|
||||
var cursor = this.$selection.getCursor(),
|
||||
word = this.getActiveWord(cursor).toLowerCase()
|
||||
|
||||
if (word == 'component') {
|
||||
this.handleCursorOnToken(cursor, word)
|
||||
}
|
||||
else if (this.tokenName) {
|
||||
this.tokenName = null
|
||||
this.tokenValue = null
|
||||
this.tokenDefinition = null
|
||||
this.tokenRange = null
|
||||
|
||||
this.$el.trigger('hide.oc.tokenexpander')
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TokenExpander.prototype.handleCursorOnToken = function(cursor, token) {
|
||||
var line = this.$session.getLine(cursor.row),
|
||||
definition = this.getTwigTokenDefinition(token, line, cursor.column)
|
||||
|
||||
if (definition) {
|
||||
|
||||
var value = this.getTwigTokenValue(token, definition[0])
|
||||
|
||||
if (value) {
|
||||
if (!this.tokenName)
|
||||
this.$el.trigger('show.oc.tokenexpander')
|
||||
|
||||
this.tokenName = token
|
||||
this.tokenValue = value
|
||||
this.tokenDefinition = definition
|
||||
this.tokenRange = this.$selection.getRange() // Used only for its row
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback must return a promise object
|
||||
*/
|
||||
TokenExpander.prototype.expandToken = function(callback) {
|
||||
var $editor = this.$editor,
|
||||
$session = this.$session,
|
||||
definition = this.tokenDefinition,
|
||||
range = this.tokenRange
|
||||
|
||||
$editor.setReadOnly(true)
|
||||
|
||||
callback(this.tokenName, this.tokenValue)
|
||||
.done(function(data){
|
||||
range.setStart(range.start.row, definition[1])
|
||||
range.setEnd(range.end.row, definition[2])
|
||||
$session.replace(range, data.result)
|
||||
})
|
||||
.always(function(){
|
||||
$editor.setReadOnly(false)
|
||||
})
|
||||
}
|
||||
|
||||
TokenExpander.prototype.getTwigTokenValue = function(tokenName, tokenString) {
|
||||
|
||||
var regex = new RegExp("^{%\\s*"+tokenName+"\\s(['"+'"'+"])([^"+'"'+"']+)(?:\\1)[^(?:%})]+%}$", "i"),
|
||||
regexMatch = regex.exec(tokenString)
|
||||
|
||||
if (regexMatch && regexMatch[2])
|
||||
return regexMatch[2]
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of [tokenString, startPos, endPos] or null
|
||||
* Eg: ['{% component "thing" %}', 0, 23]
|
||||
*/
|
||||
TokenExpander.prototype.getTwigTokenDefinition = function(token, str, pos, filter) {
|
||||
|
||||
if (!filter)
|
||||
filter = 0
|
||||
|
||||
var filteredStr = str.substring(filter),
|
||||
regex = new RegExp("{%\\s*"+token+"\\s[^(?:%})]+%}", "i"),
|
||||
regexMatch = regex.exec(filteredStr)
|
||||
|
||||
if (regexMatch) {
|
||||
var start = str.indexOf(regexMatch[0], filter),
|
||||
end = start + regexMatch[0].length
|
||||
|
||||
// Win!
|
||||
if (start < pos && end > pos)
|
||||
return [regexMatch[0], start, end]
|
||||
|
||||
// Try again
|
||||
return this.getTwigTokenDefinition(token, str, pos, end)
|
||||
}
|
||||
|
||||
// Fail
|
||||
return null
|
||||
}
|
||||
|
||||
TokenExpander.prototype.getActiveWord = function(cursor) {
|
||||
var $session = this.$session,
|
||||
wordRange = $session.getWordRange(cursor.row, cursor.column),
|
||||
word = $session.getTextRange(wordRange)
|
||||
|
||||
return word
|
||||
}
|
||||
|
||||
// TOKEN EXPANDER PLUGIN DEFINITION
|
||||
// ============================
|
||||
|
||||
var old = $.fn.tokenExpander
|
||||
|
||||
$.fn.tokenExpander = function (option) {
|
||||
var args = Array.prototype.slice.call(arguments, 1), regexMatch
|
||||
this.each(function () {
|
||||
var $this = $(this)
|
||||
var data = $this.data('oc.tokenexpander')
|
||||
var options = $.extend({}, TokenExpander.DEFAULTS, $this.data(), typeof option == 'object' && option)
|
||||
if (!data) $this.data('oc.tokenexpander', (data = new TokenExpander(this, options)))
|
||||
if (typeof option == 'string') regexMatch = data[option].apply(data, args)
|
||||
if (typeof regexMatch != 'undefined') return false
|
||||
})
|
||||
|
||||
return regexMatch ? regexMatch : this
|
||||
}
|
||||
|
||||
$.fn.tokenExpander.Constructor = TokenExpander
|
||||
|
||||
// TOKEN EXPANDER NO CONFLICT
|
||||
// =================
|
||||
|
||||
$.fn.tokenExpander.noConflict = function () {
|
||||
$.fn.tokenExpander = old
|
||||
return this
|
||||
}
|
||||
|
||||
}(window.jQuery);
|
||||
Reference in New Issue
Block a user