winter/modules/cms/assets/js/october.tokenexpander.js

184 lines
5.3 KiB
JavaScript
Raw Normal View History

2014-08-29 23:53:13 +10:00
/*
* Token Expander plugin
2014-08-29 23:53:13 +10:00
* Locates Twig tokens and replaces them with potential content inside.
*
* JavaScript API:
* $('#codeEditor').tokenExpander({ option: 'value' })
2014-08-29 23:53:13 +10:00
*
* Dependences:
* - Code Edtior (codeeditor.js)
2014-08-29 23:53:13 +10:00
*/
+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
2014-08-29 23:53:13 +10:00
}
}
}
/**
* 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
2014-08-29 23:53:13 +10:00
// Win!
if (start < pos && end > pos)
return [regexMatch[0], start, end]
2014-08-29 23:53:13 +10:00
// Try again
return this.getTwigTokenDefinition(token, str, pos, end)
}
// Fail
return null
2014-08-29 23:53:13 +10:00
}
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
}
2014-08-29 23:53:13 +10:00
}(window.jQuery);