Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preview refactor #1346

Merged
merged 8 commits into from
Jan 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions app/assets/javascripts/alchemy/alchemy.dialog.js.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -251,17 +251,19 @@ window.Alchemy.openDialog = (url, options) ->
# See Alchemy.Dialog for further options you can add to the data attribute
#
window.Alchemy.watchForDialogs = (scope = '#alchemy') ->
$(scope).on 'click', '[data-alchemy-dialog]', (e) ->
$(scope).on 'click', '[data-alchemy-dialog]', (event) ->
$this = $(this)
url = $this.attr('href')
options = $this.data('alchemy-dialog')
Alchemy.openDialog(url, options)
false
event.preventDefault()
return
$(scope).on 'click', '[data-alchemy-confirm-delete]', (event) ->
$this = $(this)
options = $this.data('alchemy-confirm-delete')
Alchemy.confirmToDeleteDialog($this.attr('href'), options)
false
event.preventDefault()
return
$(scope).on 'click', '[data-alchemy-confirm]', (event) ->
options = $(this).data('alchemy-confirm')
Alchemy.openConfirmDialog options.message, $.extend options,
Expand All @@ -271,7 +273,8 @@ window.Alchemy.watchForDialogs = (scope = '#alchemy') ->
Alchemy.pleaseWaitOverlay()
@form.submit()
return
false
event.preventDefault()
return

# Returns a FontAwesome icon for given message type
#
Expand Down
43 changes: 25 additions & 18 deletions app/assets/javascripts/alchemy/alchemy.element_editors.js.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ Alchemy.ElementEditors =
# Binds click events on several DOM elements from element editors
# Uses event delegation, so it is not necessary to rebind these events.
bindEvents: ->
@element_area.on "click", ".element-header", (e) =>
$('body').on 'click', (e) =>
@onClickBody(e)
@element_area.on "click", ".element-editor", (e) =>
@onClickElement(e)
@element_area.on "dblclick", ".element-header", (e) =>
@onDoubleClickElement(e)
Expand All @@ -39,12 +41,15 @@ Alchemy.ElementEditors =
# Selects and scrolls to element with given id in the preview window.
#
selectElementInPreview: (element_id) ->
$frame_elements = document
.getElementById("alchemy_preview_window")
.contentWindow
.jQuery("[data-alchemy-element]")
$selected_element = $frame_elements.closest("[data-alchemy-element='#{element_id}']")
$selected_element.trigger("SelectPreviewElement.Alchemy")
previewElements = document
.getElementById('alchemy_preview_window')
.contentDocument
.querySelectorAll('[data-alchemy-element]')
previewElement = Array.from(previewElements).find (element) ->
element.getAttribute('data-alchemy-element') == element_id
if previewElement
event = new Event('SelectPreviewElement.Alchemy')
previewElement.dispatchEvent(event)
return

# Selects element
Expand Down Expand Up @@ -78,8 +83,7 @@ Alchemy.ElementEditors =
# Marks an element as selected in the element window and scrolls to it.
#
selectElement: ($element) ->
$elements = $("#element_area .element-editor")
$elements.removeClass("selected")
$("#element_area .element-editor").not($element[0]).removeClass("selected")
$element.addClass("selected")
@scrollToElement($element)
return
Expand Down Expand Up @@ -168,37 +172,40 @@ Alchemy.ElementEditors =

# Event handlers

# Click event handler for element head.
onClickBody: (e) ->
frameWindow = $('#alchemy_preview_window')[0].contentWindow
element = $(e.target).parents('.element-editor')[0]
$('#element_area .element-editor').not(element).removeClass('selected')
unless element
frameWindow.postMessage('blurAlchemyElements', window.location.origin)
return

# Click event handler for element body.
#
# - Focuses the element
# - Triggers custom 'SelectPreviewElement.Alchemy' event on target element in preview frame.
#
onClickElement: (e) ->
$element = $(e.target).closest(".element-editor")
element_id = $element.attr("id").replace(/\D/g, "")
$("#element_area .element-editor").removeClass("selected")
$element.addClass("selected")
@selectElement($element)
@selectElementInPreview(element_id)
e.preventDefault()
e.stopPropagation()
false
return

# Double click event handler for element head.
onDoubleClickElement: (e) ->
id = $(e.target).closest('.element-editor').attr('id').replace(/\D/g, '')
@toggle(id)
e.preventDefault()
e.stopPropagation()
false
return

# Click event handler for element toggle icon.
onClickToggle: (e) ->
id = $(e.currentTarget).data('element-toggle')
@toggle(id)
e.preventDefault()
e.stopPropagation()
false
return

# Handles the custom 'FocusElementEditor.Alchemy' event.
#
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Alchemy.ToolbarButton = (options) ->
$lnk.click (e) ->
e.preventDefault()
options.onClick(e)
false
return
$lnk.append "<i class='icon fas fa-#{options.iconClass} fa-fw' />"
$btn.append $lnk
$btn.append "<br><label>#{options.label}</label>"
Expand Down
5 changes: 4 additions & 1 deletion app/assets/javascripts/alchemy/alchemy.gui.js.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ Alchemy.GUI =
Alchemy.Datepicker(scope)
Alchemy.Tooltips(scope)
Alchemy.Buttons.observe(scope)
Alchemy.watchForDialogs(scope)
# Dialog links use event delegation and therefore do not
# need to be re-initialized after dom elements get replaced
unless scope
Alchemy.watchForDialogs()
Alchemy.Hotkeys(scope)
Alchemy.ListFilter(scope)
Alchemy.Autocomplete.tags(scope)
Expand Down
42 changes: 0 additions & 42 deletions app/assets/javascripts/alchemy/alchemy.jquery_loader.js

This file was deleted.

129 changes: 54 additions & 75 deletions app/assets/javascripts/alchemy/alchemy.preview.js.coffee
Original file line number Diff line number Diff line change
@@ -1,92 +1,80 @@
#= require alchemy/alchemy.jquery_loader
#= require alchemy/alchemy.browser
#= require alchemy/alchemy.i18n

window.Alchemy = {} if typeof(Alchemy) is 'undefined'
window.Alchemy = Alchemy || {}

Alchemy.initAlchemyPreviewMode = ($) ->

# Setting jQueryUIs global animation duration
$.fx.speeds._default = 400
Alchemy.initAlchemyPreviewMode = ->

# The Alchemy JavaScript Object contains all Functions
$.extend Alchemy,
Object.assign Alchemy,

ElementSelector:

# defaults
scrollOffset: 20

styles:
reset:
outline: ""
"outline-offset": ""
"-moz-outline-radius": ""
default_hover:
outline: "3px solid #F0B437"
cursor: ""
hover:
outline: "2px dashed #f0b437"
"outline-offset": "4px"
cursor: "pointer"
webkit_hover:
outline: "4px auto #F0B437"
moz_hover:
"-moz-outline-radius": "3px"
default_selected:
outline: "3px solid #90B9D0"
selected:
outline: "2px dashed #90b9d0"
"outline-offset": "4px"
webkit_selected:
outline: "4px auto #90B9D0"
moz_selected:
"-moz-outline-radius": "3px"

init: ->
$elements = $("[data-alchemy-element]")
@$previewElements = $elements
$elements.mouseover (e) =>
$el = $(e.delegateTarget)
$el.attr("title", Alchemy.t('click_to_edit'))
$el.css(@getStyle("hover")) unless $el.hasClass("selected")
return
$elements.mouseout (e) =>
$el = $(e.delegateTarget)
$el.removeAttr("title")
$el.css(@getStyle("reset")) unless $el.hasClass("selected")
return
$elements.on "SelectPreviewElement.Alchemy", (e) =>
$el = $(e.delegateTarget)
# Stop the event from bubbling up to parent elements
e.stopPropagation()
@selectElement($el)
return
$elements.click (e) =>
$el = $(e.delegateTarget)
# Stop the event from bubbling up to parent elements
e.stopPropagation()
# Stop default click events from running
e.preventDefault()
# Mark current preview element as selected
@selectElement($el)
# Focus the element editor
@focusElementEditor($el)
window.addEventListener "message", (message) =>
if message.data == "blurAlchemyElements"
@blurElements()
, false
@elements = document.querySelectorAll("[data-alchemy-element]")
@elements.forEach (element) =>
element.addEventListener 'mouseover', =>
element.setAttribute('title', Alchemy.t('click_to_edit'))
unless element.classList.contains('selected')
Object.assign element.style, @getStyle('hover')
return
element.addEventListener 'mouseout', =>
element.removeAttribute('title')
unless element.classList.contains('selected')
Object.assign element.style, @getStyle('reset')
return
element.addEventListener 'SelectPreviewElement.Alchemy', =>
@selectElement(element)
return
, false
element.addEventListener 'click', (e) =>
e.stopPropagation()
e.preventDefault()
@selectElement(element)
@focusElementEditor(element)
return
return
return

# Mark element in preview frame as selected and scrolls to it.
selectElement: ($el) ->
offset = $el.offset()
@$previewElements.removeClass("selected").css(@getStyle("reset"))
$el.addClass("selected").css(@getStyle("selected"))
$("html, body").animate
scrollTop: offset.top - @scrollOffset
scrollLeft: offset.left - @scrollOffset
, 400
selectElement: (element) ->
@blurElements()
element.classList.add('selected')
Object.assign element.style, @getStyle('selected')
element.scrollIntoView
behavior: 'smooth'
block: 'start'
return

# Blur all elements in preview frame.
blurElements: ->
@elements.forEach (element) =>
element.classList.remove('selected')
Object.assign element.style, @getStyle('reset')
return
return

# Focus the element editor in the Alchemy element window.
focusElementEditor: ($el) ->
focusElementEditor: (element) ->
alchemy_window = window.parent
alchemy_$ = alchemy_window.jQuery
target_id = $el.data("alchemy-element")
$element_editor = alchemy_$("#element_#{target_id}")
target_id = element.getAttribute('data-alchemy-element')
$element_editor = alchemy_window.$("#element_#{target_id}")
elements_window = alchemy_window.Alchemy.ElementsWindow
$element_editor.trigger("FocusElementEditor.Alchemy", target_id)
elements_window.show() if elements_window.hidden
Expand All @@ -96,17 +84,8 @@ Alchemy.initAlchemyPreviewMode = ($) ->
if state == "reset"
@styles["reset"]
else
default_state_style = @styles["default_#{state}"]
browser = "webkit" if Alchemy.Browser.isWebKit
browser = "moz" if Alchemy.Browser.isFirefox
if browser
$.extend(default_state_style, @styles["#{browser}_#{state}"])
else
default_state_style
@styles[state]

Alchemy.ElementSelector.init()

if typeof(jQuery) is 'undefined'
Alchemy.loadjQuery(Alchemy.initAlchemyPreviewMode)
else
Alchemy.initAlchemyPreviewMode(jQuery)
Alchemy.initAlchemyPreviewMode()
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ Alchemy.PreviewWindow =
$reload = $('#reload_preview_button')
key 'alt+r', =>
@refresh()
$reload.click =>
$reload.click (e) =>
e.preventDefault()
@refresh()

_calculateWidth: ->
Expand Down
18 changes: 12 additions & 6 deletions app/assets/javascripts/alchemy/alchemy.tinymce.js.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,18 @@ $.extend Alchemy.Tinymce,

# Gets called after an editor instance gets intialized
#
initInstanceCallback: (inst) ->
$this = $("##{inst.id}")
parent = $this.closest('.element-editor')
parent.find('.spinner').remove()
inst.on 'dirty', (e) ->
Alchemy.setElementDirty(parent)
initInstanceCallback: (editor) ->
$this = $("##{editor.id}")
element = $this.closest('.element-editor')
element.find('.spinner').remove()
editor.on 'dirty', ->
Alchemy.setElementDirty(element)
return
editor.on 'click', (event) ->
event.target = element[0]
Alchemy.ElementEditors.onClickElement(event)
return
return

# Removes the TinyMCE editor from given dom ids.
#
Expand Down