2020-06-10 16:03:13 +00:00
function ytknsRequestJson ( url , callback , method , data , headers , handleErr , upload ) {
if ( ! callback )
callback = function ( ) { } ;
var xhr = new XMLHttpRequest ;
if ( xhr . upload && upload ) {
xhr . upload . onloadstart = function ( ev ) { upload ( 'loadstart' , ev ) ; } ;
xhr . upload . onprogress = function ( ev ) { upload ( 'progress' , ev ) } ;
xhr . upload . onload = function ( ev ) { upload ( 'load' , ev ) ; } ;
}
xhr . onreadystatechange = function ( ) {
if ( xhr . readyState !== 4 )
return ;
var json = JSON . parse ( xhr . responseText ) ;
if ( json . err && ! handleErr ) {
alert ( json . err ) ;
callback ( [ ] ) ;
} else
callback ( json ) ;
} ;
xhr . open ( method || 'GET' , url ) ;
if ( headers && headers . length > 0 )
for ( var i = 0 ; i < headers . length ; i ++ )
xhr . setRequestHeader ( headers [ i ] . name , headers [ i ] . value ) ;
xhr . send ( data || null ) ;
}
function ytknsEditorLoadEffects ( callback ) {
ytknsRequestJson ( '/zones/_effects' , callback ) ;
}
function ytknsLoadZoneInfo ( zoneId , callback ) {
ytknsRequestJson ( '/zones/' + parseInt ( zoneId ) . toString ( ) + '.json' , callback ) ;
}
function ytknsLoadUploadInfo ( uploadId , callback ) {
ytknsRequestJson ( '/uploads/' + uploadId . toString ( ) + '.json' , callback ) ;
}
function ytknsCreateUrlString ( set ) {
var parts = [ ] ;
for ( var i = 0 ; i < set . length ; i ++ )
parts . push ( encodeURIComponent ( set [ i ] . name ) + '=' + encodeURIComponent ( set [ i ] . value ) ) ;
return parts . join ( '&' ) ;
}
function ytknsCreateUrlStringPart ( name , value ) {
return { 'name' : name . toString ( ) , 'value' : (
( typeof value ) . toLowerCase ( ) === 'object'
? JSON . stringify ( value )
: value . toString ( )
) } ;
}
function ytknsZoneInfoToUrlString ( zoneInfo ) {
return ytknsCreateUrlString ( ytknsZoneInfoSerialise ( zoneInfo , ytknsCreateUrlStringPart ) ) ;
}
function ytknsZoneInfoSerialise ( zoneInfo , callback ) {
var set = [ ] ;
if ( zoneInfo ) {
set . push ( callback ( 'zone_token' , ytknsEditorToken || '' ) ) ;
set . push ( callback ( 'zone_id' , zoneInfo . id ) ) ;
set . push ( callback ( 'zone_name' , zoneInfo . name ) ) ;
set . push ( callback ( 'zone_title' , zoneInfo . title ) ) ;
if ( zoneInfo . effects && zoneInfo . effects . length > 0 ) {
for ( var i = 0 ; i < zoneInfo . effects . length ; i ++ ) {
var format = 'zone_effect[%1][%2]' . replace ( '%1' , zoneInfo . effects [ i ] . type ) ,
keys = Object . keys ( zoneInfo . effects [ i ] . values ) ;
if ( keys . length < 1 ) {
set . push ( callback ( format . replace ( '%2' , '_' ) , '_' ) ) ;
} else
for ( var j = 0 ; j < keys . length ; j ++ ) {
var key = format . replace ( '%2' , keys [ j ] ) ;
set . push ( callback ( key , zoneInfo . effects [ i ] . values [ keys [ j ] ] || '' ) ) ;
}
}
}
}
return set ;
}
function ytknsSaveZoneInfo ( zoneInfo , callback ) {
if ( ! zoneInfo || ! zoneInfo . id )
return ;
ytknsRequestJson (
'/zones/' + parseInt ( zoneInfo . id ) . toString ( ) + '.json' ,
callback ,
'POST' ,
ytknsZoneInfoToUrlString ( zoneInfo ) ,
[ { name : 'Content-Type' , value : 'application/x-www-form-urlencoded' } ]
) ;
}
function ytknsEditorPreview ( zoneInfo ) {
var formElement = document . createElement ( 'form' ) ;
formElement . action = '/zones/_preview' ;
formElement . method = 'post' ;
2020-10-16 19:24:40 +00:00
formElement . target = ytknsEditorSBS ? 'preview' : '_blank' ;
2020-06-10 16:03:13 +00:00
formElement . style . display = 'none' ;
var elements = ytknsZoneInfoSerialise ( zoneInfo , function ( name , value ) {
var inputElement = document . createElement ( 'input' ) ;
inputElement . name = name ;
inputElement . type = 'hidden' ;
inputElement . value = (
( typeof value ) . toLowerCase ( ) === 'object'
? JSON . stringify ( value )
: value . toString ( )
) ;
formElement . appendChild ( inputElement ) ;
} ) ;
document . body . appendChild ( formElement ) ;
formElement . submit ( ) ;
formElement . parentNode . removeChild ( formElement ) ;
}
function ytknsEditorCreateUpload ( file , callback , status ) {
var formData = new FormData ;
formData . append ( 'upload_token' , ytknsEditorUploadToken || '' ) ;
formData . append ( 'upload_file' , file ) ;
ytknsRequestJson (
'/uploads' ,
callback ,
'POST' ,
formData ,
null ,
true ,
status
) ;
}
var ytknsZoneInfo = null ,
ytknsEditorToken = '' ,
ytknsEditorUploadToken = '' ,
ytknsEditorElemSidebar = null ,
ytknsEditorElemSidebarButtons = null ,
ytknsEditorElemSidebarEffects = null ,
ytknsEditorElemMain = null ,
ytknsEditorElemMainTitle = null ,
ytknsEditorElemMainContainer = null ,
ytknsEditorEffects = [ ] ,
ytknsEditorIgnoreHashChange = false ,
2020-10-16 19:24:40 +00:00
ytknsEditorCleanExit = true ,
ytknsEditorSBS = false ;
2020-06-10 16:03:13 +00:00
function ytknsEditorChangeHash ( hash ) {
ytknsEditorIgnoreHashChange = true ;
location . hash = hash ;
}
function ytknsEditorBeforeUnload ( ev ) {
if ( ! ytknsEditorCleanExit ) {
ev . preventDefault ( ) ;
ev . returnValue = '' ;
}
}
function ytknsGetEffectInfoByType ( type ) {
for ( var i = 0 ; i < ytknsEditorEffects . length ; i ++ )
if ( ytknsEditorEffects [ i ] . type === type )
return ytknsEditorEffects [ i ] ;
return null ;
}
function ytknsGetEffectValueByType ( type ) {
if ( ytknsZoneInfo === null || ytknsZoneInfo . effects === null || ytknsZoneInfo . effects . length < 1 )
return null ;
for ( var i = 0 ; i < ytknsZoneInfo . effects . length ; i ++ )
if ( ytknsZoneInfo . effects [ i ] . type === type )
return ytknsZoneInfo . effects [ i ] ;
return null ;
}
function ytknsRemoveEffectValueByType ( type ) {
var info = ytknsGetEffectValueByType ( type ) ;
if ( ! info ) {
alert ( 'Tried to remove an effect that doesn\'t exist.' ) ;
return ;
}
var index = ytknsZoneInfo . effects . indexOf ( info ) ;
if ( index >= 0 )
ytknsZoneInfo . effects . splice ( index , 1 ) ;
ytknsEditorUpdateSidebarEffects ( ) ;
}
function ytknsEditorFilePickerDoUpload ( files , callback , status ) {
if ( files . length < 1 ) {
alert ( 'No file selected.' ) ;
return ;
}
var file = files [ 0 ] ;
ytknsEditorCreateUpload ( file , function ( resp ) {
if ( resp . file ) {
ytknsLoadUploadInfo ( resp . file , function ( uploadInfo ) {
callback ( uploadInfo ) ;
} ) ;
} else if ( resp . err ) {
alert ( resp . err ) ;
if ( status )
status ( - 1 , - 1 ) ;
}
} , function ( type , ev ) {
if ( status )
status ( ev . loaded , ev . total ) ;
} ) ;
}
function ytknsEditorShowFilePicker ( mimes , title , callback ) {
var container = document . createElement ( 'div' ) ;
container . classList . add ( 'ye-applet-uploads' ) ;
var progressBarContainer = document . createElement ( 'div' ) ;
progressBarContainer . classList . add ( 'ye-applet-uploads-progress' ) ;
progressBarContainer . classList . add ( 'ye-applet-uploads-hidden' ) ;
container . appendChild ( progressBarContainer ) ;
var progressBar = document . createElement ( 'progress' ) ;
progressBar . min = 0 ;
progressBar . max = 100 ;
progressBar . value = 0 ;
progressBar . classList . add ( 'ye-applet-uploads-progress-bar' ) ;
progressBarContainer . appendChild ( progressBar ) ;
var dropZone = document . createElement ( 'div' ) ,
dropZoneInner = document . createElement ( 'div' ) ;
dropZone . classList . add ( 'ye-applet-uploads-dropzone' ) ;
dropZoneInner . classList . add ( 'ye-applet-uploads-dropzone-inner' ) ;
dropZoneInner . textContent = 'Drop a file or click here!' ;
dropZone . appendChild ( dropZoneInner ) ;
container . appendChild ( dropZone ) ;
var cancel = document . createElement ( 'input' ) ;
cancel . classList . add ( 'ye-applet-uploads-cancel' ) ;
cancel . type = 'button' ;
cancel . value = 'Cancel' ;
cancel . onclick = function ( ) { callback ( null ) ; } ;
container . appendChild ( cancel ) ;
var doUpload = function ( files ) {
dropZone . classList . add ( 'ye-applet-uploads-hidden' ) ;
cancel . classList . add ( 'ye-applet-uploads-hidden' ) ;
progressBarContainer . classList . remove ( 'ye-applet-uploads-hidden' ) ;
ytknsEditorFilePickerDoUpload ( files , function ( resp ) {
dropZone . classList . remove ( 'ye-applet-uploads-hidden' ) ;
cancel . classList . remove ( 'ye-applet-uploads-hidden' ) ;
progressBarContainer . classList . add ( 'ye-applet-uploads-hidden' ) ;
callback ( resp ) ;
} , function ( loaded , total ) {
if ( loaded < 0 && total < 0 ) {
dropZone . classList . remove ( 'ye-applet-uploads-hidden' ) ;
cancel . classList . remove ( 'ye-applet-uploads-hidden' ) ;
progressBarContainer . classList . add ( 'ye-applet-uploads-hidden' ) ;
return ;
}
progressBar . value = Math . ceil ( ( loaded / total ) * 100 ) ;
} ) ;
} ;
dropZone . onclick = function ( ) {
var selector = document . createElement ( 'input' ) ;
selector . type = 'file' ;
selector . onchange = function ( ) { doUpload ( selector . files ) ; } ;
if ( mimes )
selector . accept = mimes . join ( ',' ) ;
selector . click ( ) ;
} ;
dropZone . ondragenter = function ( ev ) {
ev . preventDefault ( ) ;
ev . stopPropagation ( ) ;
dropZone . classList . add ( 'ye-applet-uploads-dropzone--active' ) ;
} ;
dropZone . ondragleave = function ( ev ) {
ev . preventDefault ( ) ;
ev . stopPropagation ( ) ;
dropZone . classList . remove ( 'ye-applet-uploads-dropzone--active' ) ;
} ;
dropZone . ondragover = function ( ev ) {
ev . preventDefault ( ) ;
ev . stopPropagation ( ) ;
dropZone . classList . add ( 'ye-applet-uploads-dropzone--active' ) ;
} ;
dropZone . ondrop = function ( ev ) {
ev . preventDefault ( ) ;
ev . stopPropagation ( ) ;
dropZone . classList . remove ( 'ye-applet-uploads-dropzone--active' ) ;
doUpload ( ev . dataTransfer . files ) ;
} ;
ytknsEditorMainSetContainer ( container , title || 'Upload File' ) ;
}
function ytknsLoadEffectEditor ( effectInfo , effectValue ) {
ytknsEditorChangeHash ( effectInfo . type ) ;
var editor = document . createElement ( 'div' ) ;
editor . classList . add ( 'ye-applet-editor' ) ;
if ( effectInfo . props . length < 1 ) {
var empty = document . createElement ( 'div' ) ;
editor . classList . add ( 'ye-applet-editor--fill' ) ;
empty . classList . add ( 'ye-applet-editor-empty' ) ;
empty . textContent = 'This effect has no properties.' ;
editor . appendChild ( empty ) ;
} else {
var properties = document . createElement ( 'div' ) ;
properties . classList . add ( 'ye-applet-editor-properties' ) ;
editor . appendChild ( properties ) ;
for ( var i = 0 ; i < effectInfo . props . length ; i ++ ) {
ytknsAddEffectEditorProperty (
properties ,
effectInfo , effectValue , effectInfo . props [ i ] ,
function ( ) { ytknsLoadEffectEditor ( effectInfo , effectValue ) ; } // there's gotta be a better way
) ;
}
}
ytknsEditorMainSetContainer ( editor , effectInfo . name ) ;
}
function ytknsAddEffectEditorProperty ( listContainer , effectInfo , effectValue , propInfo , redraw ) {
var container = document . createElement ( 'div' ) ;
container . classList . add ( 'ye-applet-editor-properties-property' ) ;
listContainer . appendChild ( container ) ;
var propTitle = document . createElement ( 'div' ) ;
propTitle . classList . add ( 'ye-applet-editor-properties-property-title' ) ;
propTitle . textContent = propInfo . title ;
container . appendChild ( propTitle ) ;
var propWrap = document . createElement ( 'div' ) ;
propWrap . classList . add ( 'ye-applet-editor-properties-property-wrap' ) ;
container . appendChild ( propWrap ) ;
switch ( propInfo . type . name ) {
case 'upload' :
var propUpload = document . createElement ( 'div' ) ;
propUpload . classList . add ( 'ye-applet-editor-properties-property-upload' ) ;
propWrap . appendChild ( propUpload ) ;
var propUploadId = document . createElement ( 'div' ) ;
propUploadId . classList . add ( 'ye-applet-editor-properties-property-upload-id' ) ;
propUploadId . textContent = effectValue . values [ propInfo . name ] || '(none)' ;
propUpload . appendChild ( propUploadId ) ;
var propUploadSelect = document . createElement ( 'div' ) ;
propUploadSelect . classList . add ( 'ye-applet-editor-properties-property-upload-select' ) ;
propUploadSelect . title = 'Upload file' ;
propUploadSelect . onclick = function ( ) {
ytknsEditorShowFilePicker ( propInfo . type . allowed || [ ] , ( 'Selecting ' + propInfo . title + ' for ' + effectInfo . name ) , function ( uploadInfo ) {
if ( uploadInfo )
effectValue . values [ propInfo . name ] = uploadInfo . id || null ;
redraw ( ) ;
} ) ;
} ;
propUpload . appendChild ( propUploadSelect ) ;
break ;
case 'bool' :
var propBool = document . createElement ( 'label' ) ;
propBool . classList . add ( 'ye-applet-editor-properties-property-bool' ) ;
propWrap . appendChild ( propBool ) ;
var propBoolToggle = document . createElement ( 'input' ) ;
propBoolToggle . classList . add ( 'ye-applet-editor-properties-property-bool-toggle' ) ;
propBoolToggle . type = 'checkbox' ;
propBoolToggle . checked = ( typeof effectValue . values [ propInfo . name ] ) . toLowerCase ( ) === 'undefined'
? ( propInfo . default || false )
: effectValue . values [ propInfo . name ] ;
propBoolToggle . onchange = function ( ) {
effectValue . values [ propInfo . name ] = propBoolToggle . checked ;
redraw ( ) ;
} ;
propBool . appendChild ( propBoolToggle ) ;
break ;
case 'int' :
case 'float' :
var propInt = document . createElement ( 'label' ) ;
propInt . classList . add ( 'ye-applet-editor-properties-property-int' ) ;
propWrap . appendChild ( propInt ) ;
var propIntInput = document . createElement ( 'input' ) ;
propIntInput . classList . add ( 'ye-applet-editor-properties-property-int-input' ) ;
propIntInput . type = 'number' ;
if ( propInfo . min )
propIntInput . min = propInfo . min ;
if ( propInfo . max )
propIntInput . max = propInfo . max ;
if ( propInfo . type . name === 'float' )
propIntInput . step = 0.01 ;
propIntInput . value = effectValue . values [ propInfo . name ] || propInfo . default || 0 ;
propIntInput . onchange = function ( ) {
effectValue . values [ propInfo . name ] = propInfo . type . name === 'int' ? parseInt ( propIntInput . value ) : parseFloat ( propIntInput . value ) ;
redraw ( ) ;
} ;
propInt . appendChild ( propIntInput ) ;
break ;
case 'select' :
var propSelect = document . createElement ( 'label' ) ;
propSelect . classList . add ( 'ye-applet-editor-properties-property-select' ) ;
propWrap . appendChild ( propSelect ) ;
var propSelectInput = document . createElement ( 'select' ) ;
propSelectInput . classList . add ( 'ye-applet-editor-properties-property-select-input' ) ;
propSelectInput . onchange = function ( ) {
effectValue . values [ propInfo . name ] = propSelectInput . value ;
redraw ( ) ;
} ;
propSelect . appendChild ( propSelectInput ) ;
var propSelectOptionsKeys = Object . keys ( propInfo . type . options ) ,
propSelectOptionsValues = Object . values ( propInfo . type . options ) ;
for ( var i = 0 ; i < propSelectOptionsKeys . length ; i ++ ) {
var propSelectOption = document . createElement ( 'option' ) ;
propSelectOption . value = propSelectOptionsKeys [ i ] ;
propSelectOption . textContent = propSelectOptionsValues [ i ] ;
propSelectOption . selected = ( effectValue . values [ propInfo . name ] || propInfo . default ) === propSelectOptionsKeys [ i ] ;
propSelectInput . appendChild ( propSelectOption ) ;
}
break ;
case 'colour' :
var propColour = document . createElement ( 'label' ) ;
propColour . classList . add ( 'ye-applet-editor-properties-property-colour' ) ;
propWrap . appendChild ( propColour ) ;
var propColourInput = document . createElement ( 'input' ) ;
propColourInput . type = 'color' ;
propColourInput . value = '#' + ( effectValue . values [ propInfo . name ] || 0 ) . toString ( 16 ) . padStart ( 6 , '0' ) ;
propColourInput . classList . add ( 'ye-applet-editor-properties-property-colour-input' ) ;
propColourInput . onchange = function ( ) {
effectValue . values [ propInfo . name ] = parseInt ( propColourInput . value . substring ( 1 ) , 16 ) ;
redraw ( ) ;
} ;
propColour . appendChild ( propColourInput ) ;
break ;
case 'string' :
var propString = document . createElement ( 'label' ) ;
propString . classList . add ( 'ye-applet-editor-properties-property-string' ) ;
propWrap . appendChild ( propString ) ;
var propStringInput = document . createElement ( 'input' ) ;
propStringInput . type = 'text' ;
if ( propInfo . type . min )
propStringInput . minLength = propInfo . type . min ;
if ( propInfo . type . max )
propStringInput . maxLength = propInfo . type . max ;
propStringInput . value = effectValue . values [ propInfo . name ] || '' ;
propStringInput . classList . add ( 'ye-applet-editor-properties-property-string-input' ) ;
propStringInput . onchange = function ( ) {
effectValue . values [ propInfo . name ] = propStringInput . value ;
redraw ( ) ;
} ;
propString . appendChild ( propStringInput ) ;
break ;
case 'gradient' :
if ( ! effectValue . values [ propInfo . name ] )
effectValue . values [ propInfo . name ] = { } ;
var propGrad = document . createElement ( 'div' ) ;
propGrad . classList . add ( 'ye-applet-editor-properties-property-gradient' ) ;
propWrap . appendChild ( propGrad ) ;
var propGradPreview = document . createElement ( 'div' ) ;
propGradPreview . classList . add ( 'ye-applet-editor-properties-property-gradient-preview' ) ;
propGrad . appendChild ( propGradPreview ) ;
var propGradDirection = document . createElement ( 'div' ) ;
propGradDirection . classList . add ( 'ye-applet-editor-properties-property-gradient-direction' ) ;
propGrad . appendChild ( propGradDirection ) ;
var propGradDirectionCircle = document . createElement ( 'div' ) ;
propGradDirectionCircle . classList . add ( 'ye-applet-editor-properties-property-gradient-direction-circle' ) ;
propGradDirection . appendChild ( propGradDirectionCircle ) ;
var propGradDirectionCircleValue = document . createElement ( 'div' ) ;
propGradDirectionCircleValue . classList . add ( 'ye-applet-editor-properties-property-gradient-direction-circle-value' ) ;
propGradDirectionCircle . appendChild ( propGradDirectionCircleValue ) ;
var propGradDirectionCircleIndicator = document . createElement ( 'div' ) ;
propGradDirectionCircleIndicator . classList . add ( 'ye-applet-editor-properties-property-gradient-direction-circle-indicator' ) ;
propGradDirectionCircleValue . appendChild ( propGradDirectionCircleIndicator ) ;
var propGradDirectionValue = document . createElement ( 'input' ) ;
propGradDirectionValue . classList . add ( 'ye-applet-editor-properties-property-gradient-direction-input' ) ;
propGradDirectionValue . type = 'number' ;
propGradDirectionValue . min = 0 ;
propGradDirectionValue . max = 359 ;
propGradDirectionValue . value = 0 ;
propGradDirection . appendChild ( propGradDirectionValue ) ;
var propGradRedrawPreview = function ( ) {
propGradPreview . style . backgroundImage = ytknsEditorGradientCSS ( effectValue . values [ propInfo . name ] ) ;
} ;
var propGradDirectionSet = function ( val ) {
val = parseInt ( val ) ;
effectValue . values [ propInfo . name ] . d = val ;
if ( propGradDirectionValue . value != val )
propGradDirectionValue . value = val ;
propGradDirectionCircleValue . style . transform = 'rotate(' + val + 'deg)' ;
propGradRedrawPreview ( ) ;
} ;
propGradDirectionSet ( effectValue . values [ propInfo . name ] . d || 0 ) ;
propGradDirectionValue . onchange = function ( ) {
propGradDirectionSet ( propGradDirectionValue . value ) ;
} ;
var propGradDirectionCircleMouseEvent = function ( ev ) {
if ( ( ev . buttons & 1 ) < 1 )
return ;
var rect = ev . target . getBoundingClientRect ( ) ,
y = ev . layerY - ( rect . height / 2 ) ,
x = ev . layerX - ( rect . width / 2 ) ,
deg = Math . atan2 ( x , y ) * 180 / Math . PI ,
val = 180 - parseInt ( deg ) ;
propGradDirectionSet ( val ) ;
} ;
propGradDirectionCircle . onmousedown = propGradDirectionCircleMouseEvent ;
propGradDirectionCircle . onmousemove = propGradDirectionCircleMouseEvent ;
var propGradPoints = document . createElement ( 'div' ) ;
propGradPoints . classList . add ( 'ye-applet-editor-properties-property-gradient-points' ) ;
propGrad . appendChild ( propGradPoints ) ;
var propGradPointAdd = function ( point ) {
if ( ! point )
point = { } ;
if ( ( typeof point . c ) . toLowerCase ( ) === 'undefined' )
point . c = parseInt ( 0xFFFFFF * Math . random ( ) ) ;
if ( ( typeof point . o ) . toLowerCase ( ) === 'undefined' )
point . o = parseInt ( 100 * Math . random ( ) ) ;
var propGradPoint = document . createElement ( 'div' ) ;
propGradPoint . classList . add ( 'ye-applet-editor-properties-property-gradient-points-point' ) ;
propGradPoints . appendChild ( propGradPoint ) ;
var propGradPointActions = document . createElement ( 'div' ) ;
propGradPointActions . classList . add ( 'ye-applet-editor-properties-property-gradient-points-point-actions' ) ;
propGradPoint . appendChild ( propGradPointActions ) ;
var propGradPointActionsAdd = function ( name , title , action ) {
var propGradPointAction = document . createElement ( 'div' ) ;
propGradPointAction . classList . add ( 'ye-applet-editor-properties-property-gradient-points-point-actions-action' ) ;
propGradPointAction . classList . add ( 'ye-applet-editor-properties-property-gradient-points-point-actions-action--' + name ) ;
propGradPointAction . title = title ;
propGradPointAction . onclick = function ( ) { if ( action ) action ( ) ; } ;
propGradPointActions . appendChild ( propGradPointAction ) ;
} ;
propGradPointActionsAdd ( 'delete' , 'Delete' , function ( ) {
var index = effectValue . values [ propInfo . name ] . p . indexOf ( point ) ;
if ( index < 0 )
return ;
effectValue . values [ propInfo . name ] . p . splice ( index , 1 ) ;
propGradPoints . removeChild ( propGradPoint ) ;
propGradRedrawPreview ( ) ;
} ) ;
var propGradPointColour = document . createElement ( 'label' ) ;
propGradPointColour . classList . add ( 'ye-applet-editor-properties-property-gradient-points-point-colour' ) ;
propGradPoint . appendChild ( propGradPointColour ) ;
var propGradPointColourValue = document . createElement ( 'input' ) ;
propGradPointColourValue . type = 'color' ;
propGradPointColourValue . value = '#' + point . c . toString ( 16 ) . padStart ( 6 , '0' ) ;
propGradPointColourValue . classList . add ( 'ye-applet-editor-properties-property-gradient-points-point-colour-value' ) ;
propGradPointColourValue . onchange = function ( ) {
point . c = parseInt ( propGradPointColourValue . value . substring ( 1 ) , 16 ) ;
propGradPointColour . style . backgroundColor = propGradPointColourValue . value ;
propGradRedrawPreview ( ) ;
} ;
propGradPointColour . appendChild ( propGradPointColourValue ) ;
propGradPointColour . style . backgroundColor = propGradPointColourValue . value ;
var propGradPointOffset = document . createElement ( 'input' ) ;
propGradPointOffset . type = 'range' ;
propGradPointOffset . classList . add ( 'ye-applet-editor-properties-property-gradient-points-point-offset-range' ) ;
propGradPointOffset . value = 0 ;
propGradPointOffset . min = 0 ;
propGradPointOffset . max = 100 ;
propGradPoint . appendChild ( propGradPointOffset ) ;
var propGradPointOffsetNum = document . createElement ( 'input' ) ;
propGradPointOffsetNum . type = 'number' ;
propGradPointOffsetNum . classList . add ( 'ye-applet-editor-properties-property-gradient-points-point-offset-numeric' ) ;
propGradPointOffsetNum . value = 0 ;
propGradPointOffsetNum . min = 0 ;
propGradPointOffsetNum . max = 100 ;
propGradPoint . appendChild ( propGradPointOffsetNum ) ;
var propGradPointOffsetIsSetting = false ,
propGradPointOffsetSet = function ( val ) {
if ( propGradPointOffsetIsSetting )
return ;
propGradPointOffsetIsSetting = true ;
val = parseInt ( val ) ;
propGradPointOffset . value = propGradPointOffsetNum . value = point . o = val ;
propGradRedrawPreview ( ) ;
propGradPointOffsetIsSetting = false ;
} ;
propGradPointOffsetSet ( point . o ) ;
propGradPointOffset . onchange = function ( ) {
propGradPointOffsetSet ( propGradPointOffset . value ) ;
} ;
propGradPointOffsetNum . onchange = function ( ) {
propGradPointOffsetSet ( propGradPointOffsetNum . value ) ;
} ;
} ;
var propGradPointAddButton = document . createElement ( 'button' ) ;
propGradPointAddButton . classList . add ( 'ye-applet-editor-properties-property-gradient-points-add' ) ;
propGradPointAddButton . onclick = function ( ) {
var point = { } ;
if ( ! effectValue . values [ propInfo . name ] . p )
effectValue . values [ propInfo . name ] . p = [ ] ;
effectValue . values [ propInfo . name ] . p . push ( point ) ;
propGradPointAdd ( point ) ;
propGradRedrawPreview ( ) ;
} ;
propGradDirection . appendChild ( propGradPointAddButton ) ;
var propGradPointAddButtonIcon = document . createElement ( 'div' ) ;
propGradPointAddButtonIcon . classList . add ( 'ye-applet-editor-properties-property-gradient-points-add-icon' ) ;
propGradPointAddButton . appendChild ( propGradPointAddButtonIcon ) ;
var propGradPointAddButtonText = document . createElement ( 'div' ) ;
propGradPointAddButtonText . classList . add ( 'ye-applet-editor-properties-property-gradient-points-add-text' ) ;
propGradPointAddButtonText . textContent = 'Add gradient point' ;
propGradPointAddButton . appendChild ( propGradPointAddButtonText ) ;
if ( effectValue . values [ propInfo . name ] . p )
for ( var i = 0 ; i < effectValue . values [ propInfo . name ] . p . length ; i ++ )
propGradPointAdd ( effectValue . values [ propInfo . name ] . p [ i ] ) ;
break ;
default :
var propNone = document . createElement ( 'div' ) ;
propNone . classList . add ( 'ye-applet-editor-properties-property-none' ) ;
propNone . textContent = 'There is no handler available for this property type.' ;
propWrap . appendChild ( propNone ) ;
break ;
}
var propDefault = document . createElement ( 'div' ) ;
propDefault . classList . add ( 'ye-applet-editor-properties-property-reset' ) ;
propDefault . title = 'Reset' ;
propDefault . onclick = function ( ) {
effectValue . values [ propInfo . name ] = propInfo . default ;
redraw ( ) ;
} ;
propWrap . appendChild ( propDefault ) ;
}
function ytknsEditorGradientCSS ( obj ) {
var str = 'linear-gradient(' + ( obj . d || 0 ) . toString ( ) + 'deg, ' ,
points = [ ] ;
if ( obj . p )
for ( var i = 0 ; i < obj . p . length ; i ++ )
points . push ( '#' + ( obj . p [ i ] . c || 0 ) . toString ( 16 ) . padStart ( 6 , '0' ) + ' ' + ( obj . p [ i ] . o || 0 ) . toString ( ) + '%' ) ;
return str + points . join ( ', ' ) + ')' ;
}
function ytknsEditorAddSidebarButton ( className , title , callback ) {
var button = document . createElement ( 'div' ) ;
button . classList . add ( 'ye-sidebar-buttons-button' ) ;
button . classList . add ( 'ye-sidebar-buttons-button--' + className ) ;
button . title = title ;
button . onclick = callback ;
ytknsEditorElemSidebarButtons . appendChild ( button ) ;
}
function ytknsEditorAddSidebarButtonSeparator ( ) {
var separator = document . createElement ( 'div' ) ;
separator . classList . add ( 'ye-sidebar-buttons-separator' ) ;
ytknsEditorElemSidebarButtons . appendChild ( separator ) ;
}
function ytknsEditorAddSidebarEffect ( effectValue ) {
var effectInfo = ytknsGetEffectInfoByType ( effectValue . type ) ;
if ( ! effectInfo ) {
alert ( 'Attempted to add unregistered effect.' ) ;
return ;
}
var effect = document . createElement ( 'div' ) ;
effect . classList . add ( 'ye-sidebar-effects-effect' ) ;
ytknsEditorElemSidebarEffects . appendChild ( effect ) ;
var effectName = document . createElement ( 'div' ) ;
effectName . classList . add ( 'ye-sidebar-effects-effect-name' ) ;
effectName . textContent = effectInfo . name ;
effect . appendChild ( effectName ) ;
var effectActions = document . createElement ( 'div' ) ;
effectActions . classList . add ( 'ye-sidebar-effects-effect-actions' ) ;
effect . appendChild ( effectActions ) ;
ytknsEditorAddSidebarEffectAction ( effectActions , 'edit' , 'Edit Effect' , function ( ) {
ytknsLoadEffectEditor ( effectInfo , effectValue ) ;
} ) ;
ytknsEditorAddSidebarEffectAction ( effectActions , 'delete' , 'Delete Effect' , function ( ) {
var previous = ytknsEditorMainClone ( ) ;
ytknsEditorMainShowEffectDeleteConfirm ( effectInfo , function ( accept ) {
if ( accept ) {
ytknsRemoveEffectValueByType ( effectValue . type ) ;
ytknsEditorMainShowWelcome ( ) ;
} else {
ytknsEditorMainRestore ( previous ) ;
}
} ) ;
} ) ;
}
function ytknsEditorMainShowEffectDeleteConfirm ( effectInfo , callback ) {
var confirmation = document . createElement ( 'div' ) ,
text = confirmation . appendChild ( document . createElement ( 'div' ) ) ,
actions = confirmation . appendChild ( document . createElement ( 'div' ) ) ;
confirmation . classList . add ( 'ye-main-effect-delete-confirm' ) ;
text . classList . add ( 'ye-main-effect-delete-confirm-text' ) ;
text . textContent = 'Are you sure you want to delete "' + effectInfo . name + '"?' ;
actions . classList . add ( 'ye-main-effect-delete-confirm-actions' ) ;
var accept = document . createElement ( 'div' ) ;
accept . classList . add ( 'ye-main-effect-delete-confirm-actions-action' ) ;
accept . classList . add ( 'ye-main-effect-delete-confirm-actions-action--accept' ) ;
accept . textContent = 'Yes' ;
accept . onclick = function ( ) { callback ( true ) ; } ;
actions . appendChild ( accept ) ;
var deny = document . createElement ( 'div' ) ;
deny . classList . add ( 'ye-main-effect-delete-confirm-actions-action' ) ;
deny . classList . add ( 'ye-main-effect-delete-confirm-actions-action--deny' ) ;
deny . textContent = 'No' ;
deny . onclick = function ( ) { callback ( false ) ; } ;
actions . appendChild ( deny ) ;
ytknsEditorMainSetContainer ( confirmation , 'Delete effect' ) ;
}
function ytknsEditorAddSidebarEffectAction ( container , className , title , callback ) {
var action = document . createElement ( 'div' ) ;
action . classList . add ( 'ye-sidebar-effects-effect-actions-action' ) ;
action . classList . add ( 'ye-sidebar-effects-effect-actions-action--' + className ) ;
action . title = title ;
action . onclick = callback ;
container . appendChild ( action ) ;
}
function ytknsEditorUpdateSidebarEffects ( ) {
ytknsEditorElemSidebarEffects . innerHTML = '' ;
if ( ytknsZoneInfo == null || ytknsZoneInfo . effects == null || ytknsZoneInfo . effects . length < 1 ) {
var nothing = document . createElement ( 'div' ) ;
nothing . classList . add ( 'ye-sidebar-effects-empty' ) ;
nothing . textContent = 'You have not added any effects yet.' ;
ytknsEditorElemSidebarEffects . appendChild ( nothing ) ;
} else {
for ( var i = 0 ; i < ytknsZoneInfo . effects . length ; i ++ )
ytknsEditorAddSidebarEffect ( ytknsZoneInfo . effects [ i ] ) ;
}
}
function ytknsShowDetailsEdit ( ) {
ytknsEditorChangeHash ( 'details' ) ;
var container = document . createElement ( 'div' ) ;
container . classList . add ( 'ye-main-details' ) ;
var fieldsElem = document . createElement ( 'div' ) ;
fieldsElem . classList . add ( 'ye-main-details-fields' ) ;
container . appendChild ( fieldsElem ) ;
var fields = [
{ name : 'Zone ID' , value : ytknsZoneInfo . id } ,
{ name : 'Subdomain' , value : ytknsZoneInfo . name , suffix : '.' + location . host } ,
{ name : 'Title' , value : ytknsZoneInfo . title , max : 255 , edit : function ( val ) {
ytknsZoneInfo . title = val ;
} } ,
] ;
for ( var i = 0 ; i < fields . length ; i ++ ) {
var field = fields [ i ] ,
fieldElem = document . createElement ( 'div' ) ;
fieldElem . classList . add ( 'ye-main-details-fields-field' ) ;
var fieldName = document . createElement ( 'div' ) ;
fieldName . classList . add ( 'ye-main-details-fields-field-name' ) ;
fieldName . textContent = field . name + ':' ;
fieldElem . appendChild ( fieldName ) ;
var fieldWrap = document . createElement ( 'div' ) ;
fieldWrap . classList . add ( 'ye-main-details-fields-field-wrap' ) ;
fieldElem . appendChild ( fieldWrap ) ;
var fieldInput = document . createElement ( 'input' ) ;
fieldInput . classList . add ( 'ye-main-details-fields-field-input' ) ;
fieldInput . type = 'text' ;
fieldInput . value = field . value ;
if ( field . max )
fieldInput . maxLength = field . max ;
if ( field . edit ) {
var onedit = field . edit ;
fieldInput . onchange = function ( ev ) {
onedit ( ev . target . value ) ;
} ;
} else {
fieldInput . readOnly = true ;
fieldElem . classList . add ( 'ye-main-details-fields-field--readonly' ) ;
}
fieldWrap . appendChild ( fieldInput ) ;
if ( field . suffix )
fieldWrap . appendChild ( document . createTextNode ( field . suffix ) ) ;
fieldsElem . appendChild ( fieldElem ) ;
}
ytknsEditorMainSetContainer ( container , 'Zone information' ) ;
}
function ytknsEditorMainGetTitle ( ) {
return ytknsEditorElemMainTitle . textContent ;
}
function ytknsEditorMainSetTitle ( title ) {
ytknsEditorElemMainTitle . textContent = title ;
}
function ytknsEditorMainGetContainer ( ) {
return ytknsEditorElemMainContainer . firstChild ;
}
function ytknsEditorMainSetContainer ( child , title ) {
if ( title )
ytknsEditorMainSetTitle ( title ) ;
ytknsEditorElemMainContainer . innerHTML = '' ;
ytknsEditorElemMainContainer . appendChild ( child ) ;
2020-10-16 19:24:40 +00:00
if ( ytknsEditorSBS )
ytknsEditorPreview ( ytknsZoneInfo ) ;
2020-06-10 16:03:13 +00:00
}
function ytknsEditorMainClone ( ) {
return {
'title' : ytknsEditorMainGetTitle ( ) ,
'content' : ytknsEditorMainGetContainer ( ) . cloneNode ( true ) ,
} ;
}
function ytknsEditorMainRestore ( clone ) {
ytknsEditorMainSetContainer ( clone . content , clone . title ) ;
}
function ytknsEditorMainShowWelcome ( ) {
var welcome = document . createElement ( 'div' ) ;
welcome . classList . add ( 'ye-main-welcome' ) ;
var welcomeH1 = document . createElement ( 'h1' ) ;
welcomeH1 . classList . add ( 'ye-main-welcome-h1' ) ;
welcomeH1 . textContent = 'Welcome!' ;
welcome . appendChild ( welcomeH1 ) ;
var welcomeP = document . createElement ( 'p' ) ;
welcomeP . classList . add ( 'ye-main-welcome-p' ) ;
welcomeP . textContent = 'Select a tool in the sidebar to get started.' ;
welcome . appendChild ( welcomeP ) ;
ytknsEditorMainSetContainer ( welcome , 'Welcome to the YTKNS Editor' ) ;
}
function ytknsEditorMainShowEffectList ( ) {
ytknsEditorChangeHash ( 'add' ) ;
var container = document . createElement ( 'div' ) ;
container . classList . add ( 'ye-applet-effects' ) ;
var effects = document . createElement ( 'div' ) ;
effects . classList . add ( 'ye-applet-effects-list' ) ;
container . appendChild ( effects ) ;
for ( var i = 0 ; i < ytknsEditorEffects . length ; i ++ ) {
var effectInfo = ytknsEditorEffects [ i ] ,
effectValue = ytknsGetEffectValueByType ( effectInfo . type ) ,
effectElement = document . createElement ( 'div' ) ,
effectUsed = effectValue !== null ;
effectElement . classList . add ( 'ye-applet-effects-list-item' ) ;
if ( effectUsed )
effectElement . classList . add ( 'ye-applet-effects-list-item--used' ) ;
var effectName = document . createElement ( 'div' ) ;
effectName . classList . add ( 'ye-applet-effects-list-item-name' ) ;
effectName . textContent = effectInfo . name ;
effectElement . appendChild ( effectName ) ;
var effectActions = document . createElement ( 'div' ) ;
effectActions . classList . add ( 'ye-applet-effects-list-item-actions' ) ;
effectElement . appendChild ( effectActions ) ;
if ( ! effectUsed ) {
var effectActionAdd = document . createElement ( 'div' ) ;
effectActionAdd . classList . add ( 'ye-applet-effects-list-item-actions-action' ) ;
effectActionAdd . classList . add ( 'ye-applet-effects-list-item-actions-action--add' ) ;
effectActionAdd . title = 'Add Effect' ;
( function ( ) { // javascript is very cool and good
var effectInfoCopy = effectInfo ;
effectActionAdd . onclick = function ( ) {
var effectValueNew = ytknsEditorAddNewEffect ( effectInfoCopy ) ;
ytknsEditorUpdateSidebarEffects ( ) ;
ytknsLoadEffectEditor ( effectInfoCopy , effectValueNew ) ;
} ;
} ) ( ) ;
effectActions . appendChild ( effectActionAdd ) ;
}
effects . appendChild ( effectElement ) ;
}
ytknsEditorMainSetContainer ( container , 'Available effects' ) ;
}
function ytknsEditorAddNewEffect ( effectInfo ) {
var effectValue = {
type : effectInfo . type ,
values : { } ,
} ;
for ( var i = 0 ; i < effectInfo . props . length ; i ++ ) {
var propInfo = effectInfo . props [ i ] ;
effectValue . values [ propInfo . name ] = propInfo . default || '' ;
}
ytknsZoneInfo . effects . push ( effectValue ) ;
return effectValue ;
}
function ytknsEditorConfirmReloadZoneInfo ( zoneId ) {
if ( confirm ( 'Are you sure you want to undo any changes you\'ve made?' ) )
ytknsEditorReloadZoneInfo ( zoneId ) ;
}
function ytknsEditorReloadZoneInfo ( zoneId , onComplete ) {
ytknsEditorChangeHash ( '' ) ;
ytknsEditorMainShowWelcome ( ) ;
ytknsEditorLoadEffects ( function ( effects ) {
ytknsEditorEffects = effects ;
ytknsLoadZoneInfo ( zoneId , function ( zoneInfo ) {
ytknsZoneInfo = zoneInfo ;
ytknsEditorUpdateSidebarEffects ( ) ;
if ( onComplete )
onComplete ( ) ;
} ) ;
} ) ;
}
function ytknsEditorSwitchString ( str ) {
switch ( str ) {
case '' :
ytknsEditorMainShowWelcome ( ) ;
break ;
case 'add' :
ytknsEditorMainShowEffectList ( ) ;
break ;
case 'details' :
ytknsShowDetailsEdit ( ) ;
break ;
default :
var openEffectInfo = ytknsGetEffectInfoByType ( str ) ;
if ( openEffectInfo ) {
var openEffectValue = ytknsGetEffectValueByType ( str ) ;
ytknsLoadEffectEditor ( openEffectInfo , openEffectValue ) ;
}
break ;
}
}
function ytknsEditorHashChange ( ev ) {
if ( ! ytknsEditorIgnoreHashChange )
ytknsEditorSwitchString ( location . hash . substring ( 1 ) ) ;
ytknsEditorIgnoreHashChange = false ;
}
2020-10-16 19:24:40 +00:00
function ytknsEditorMain ( container , zoneId , editorToken , uploadToken , sideBySide ) {
2020-06-10 16:03:13 +00:00
if ( navigator . userAgent . match ( /mobile/gi ) && ! confirm ( "The editor is not designed to be used on phones whatsoever.\r\nHit OK to continue anyway or cancel to whereever you came from." ) ) {
history . go ( - 1 ) ;
return ;
}
window . onhashchange = ytknsEditorHashChange ;
window . onbeforeunload = ytknsEditorBeforeUnload ;
ytknsEditorToken = editorToken ;
ytknsEditorUploadToken = uploadToken ;
2020-10-16 19:24:40 +00:00
ytknsEditorSBS = sideBySide ;
2020-06-10 16:03:13 +00:00
container . innerHTML = '' ;
container . classList . add ( 'ye' ) ;
ytknsEditorElemSidebar = container . appendChild ( document . createElement ( 'div' ) ) ;
ytknsEditorElemSidebar . classList . add ( 'ye-sidebar' ) ;
ytknsEditorElemSidebarButtons = ytknsEditorElemSidebar . appendChild ( document . createElement ( 'div' ) ) ;
ytknsEditorElemSidebarButtons . classList . add ( 'ye-sidebar-buttons' ) ;
ytknsEditorAddSidebarButton ( 'save' , 'Save' , function ( ) {
ytknsSaveZoneInfo ( ytknsZoneInfo , function ( res ) {
if ( res . msg )
alert ( res . msg ) ;
} ) ;
} ) ;
ytknsEditorAddSidebarButton ( 'cancel' , 'Cancel' , function ( ) { location . assign ( '/zones?f=my' ) ; } ) ;
ytknsEditorAddSidebarButton ( 'reset' , 'Undo Changes' , function ( ) { ytknsEditorConfirmReloadZoneInfo ( zoneId ) ; } ) ;
ytknsEditorAddSidebarButton ( 'edit' , 'Edit Details' , function ( ) { ytknsShowDetailsEdit ( ) ; } ) ;
ytknsEditorAddSidebarButtonSeparator ( ) ;
ytknsEditorAddSidebarButton ( 'preview' , 'Show Preview' , function ( ) { ytknsEditorPreview ( ytknsZoneInfo ) ; } ) ;
ytknsEditorAddSidebarButton ( 'live' , 'View Live' , function ( ) { window . open ( '//%1.%2' . replace ( '%2' , location . host ) . replace ( '%1' , ytknsZoneInfo . name ) ) ; } ) ;
ytknsEditorAddSidebarButtonSeparator ( ) ;
ytknsEditorAddSidebarButton ( 'add' , 'Add Effect' , function ( ) { ytknsEditorMainShowEffectList ( ) ; } ) ;
ytknsEditorElemSidebarEffects = ytknsEditorElemSidebar . appendChild ( document . createElement ( 'div' ) ) ;
ytknsEditorElemSidebarEffects . classList . add ( 'ye-sidebar-effects' ) ;
ytknsEditorUpdateSidebarEffects ( ) ;
ytknsEditorElemMain = container . appendChild ( document . createElement ( 'div' ) ) ;
ytknsEditorElemMain . classList . add ( 'ye-main' ) ;
ytknsEditorElemMainTitle = ytknsEditorElemMain . appendChild ( document . createElement ( 'div' ) ) ;
ytknsEditorElemMainTitle . classList . add ( 'ye-main-title' ) ;
ytknsEditorElemMainContainer = ytknsEditorElemMain . appendChild ( document . createElement ( 'div' ) ) ;
ytknsEditorElemMainContainer . classList . add ( 'ye-main-container' ) ;
var goToEditor = location . hash . substring ( 1 ) ;
ytknsEditorReloadZoneInfo ( zoneId , function ( ) {
ytknsEditorSwitchString ( goToEditor ) ;
} ) ;
}