1{% extends project_specific|yesno:"baseprojectspecificpage.html,baseprojectpage.html" %} 2{% load projecttags %} 3{% load humanize %} 4 5{% block title %} BitBake variables - {{project.name}} - Toaster {% endblock %} 6{% block projectinfomain %} 7 8<h2>Bitbake variables</h2> 9<div> 10 <dl> 11 {% if distro_defined %} 12 <dt> 13 <span class="js-config-var-name js-config-var-managed-name">DISTRO</span> 14 <span class="glyphicon glyphicon-question-sign get-help" title="The short name of the distribution. If the variable is blank, meta/conf/distro/defaultsetup.conf will be used"></span> 15 </dt> 16 <dd class="variable-list"> 17 <span class="lead" id="distro">{{distro}}</span> 18 <span class="glyphicon glyphicon-edit" id="change-distro-icon"></span> 19 <form id="change-distro-form" class="form-inline" style="display:none;"> 20 <div id="edit-distro-name-div" class="form-group"> 21 <input type="text" class="form-control" id="new-distro" value="{{distro}}"> 22 </div> 23 <button id="apply-change-distro" class="btn btn-default" type="button">Save</button> 24 <button id="cancel-change-distro" type="button" class="btn btn-link">Cancel</button> 25 <span class="help-block" id="distro-error-message"></span> 26 </form> 27 </dd> 28 {% endif %} 29 30 {% if dl_dir_defined %} 31 <dt> 32 <span class="js-config-var-name js-config-var-managed-name">DL_DIR</span> 33 <span class="glyphicon glyphicon-question-sign get-help" title="Absolute path to the directory used to store downloads required for your builds. By default, Toaster projects share the same downloads directory"></span> 34 </dt> 35 <dd class="variable-list"> 36 <span id="dl_dir" class="lead {% if not dl_dir %} text-muted {% endif %}">{% if dl_dir %}{{dl_dir}}{%else%}Not set{%endif%}</span> 37 <span class="glyphicon glyphicon-edit" id="change-dl_dir-icon"></span> 38 <form id="change-dl_dir-form" class="form-inline" style="display:none;"> 39 <div class="form-group" id="validate-dl_dir"> 40 <input type="text" class="form-control" id="new-dl_dir" placeholder="Type an absolute path"> 41 </div> 42 <button id="apply-change-dl_dir" class="btn btn-default" type="button">Save</button> 43 <button id="cancel-change-dl_dir" type="button" class="btn btn-link">Cancel</button> 44 <p class="help-block" id="hintError-dl_dir" style="display:none;">The directory path cannot include spaces or any of these characters: \ ? % * : | " " < ></p> 45 <p class="help-block" id="hintError-initialChar-dl_dir" style="display:none;">The directory path should either start with a /, e.g. /home/toaster/downloads; or with a variable, e.g. ${TOPDIR}/downloads.</p> 46 </form> 47 </dd> 48 {% endif %} 49 50 {% if fstypes_defined %} 51 <dt> 52 <span class="js-config-var-name js-config-var-managed-name">IMAGE_FSTYPES</span> 53 <span class="glyphicon glyphicon-question-sign get-help" title="Formats of root file system images that you want to create"></span> 54 </dt> 55 <dd class="variable-list"> 56 <span class="lead" id="image_fstypes">{{fstypes}}</span> 57 <span class="glyphicon glyphicon-edit" id="change-image_fstypes-icon"></span> 58 <form id="change-image_fstypes-form" style="display:none;"> 59 <label>Type the image types you want to build:</label> 60 <div class="form-group form-inline" id="validate-image_fstypes"> 61 <input type="text" class="form-control "id="new-imagefs_types"> 62 <button id="apply-change-image_fstypes" type="button" class="btn btn-default">Save</button> 63 <button id="cancel-change-image_fstypes" type="button" class="btn btn-link">Cancel</button> 64 </div> 65 <p class="help-block text-danger" style="display:none;" id="hintError-image-fs_type">A valid image type cannot include underscores</p> 66 <p class="help-block text-danger" style="display:none;" id="fstypes-error-message">You must select at least one image type</p> 67 <label>Or choose from known image types:</label> 68 <input id="filter-image_fstypes" type="text" placeholder="Search image types" class="form-control"> 69 <div id="all-image_fstypes" class="scrolling"></div> 70 </form> 71 </dd> 72 {% endif %} 73 74 {% if image_install_append_defined %} 75 <dt> 76 <span class="js-config-var-name js-config-var-managed-name">IMAGE_INSTALL_append</span> 77 <span class="glyphicon glyphicon-question-sign get-help" title="Specifies additional packages to install into an image. If your build creates more than one image, the packages will be installed in all of them"></span> 78 </dt> 79 <dd class="variable-list"> 80 <span id="image_install" class="lead {% if not image_install_append %} text-muted {%endif%}">{% if image_install_append %}{{image_install_append}}{%else%}Not set{%endif%}</span> 81 <span class="glyphicon glyphicon-edit" id="change-image_install-icon"></span> 82 <span class="glyphicon glyphicon-trash" id="delete-image_install-icon" {% if image_install_append %}{%else%}style="display:none;"{%endif%}></span> 83 <form id="change-image_install-form" class="form-inline" style="display:none;"> 84 <div class="row"> 85 <div class="col-md-4"> 86 <span class="help-block">To set IMAGE_INSTALL_append to more than one package, type the package names separated by a space.</span> 87 </div> 88 </div> 89 <div class="form-group"> 90 <input type="text" class="form-control" id="new-image_install" placeholder="Type one or more package names"> 91 </div> 92 <button id="apply-change-image_install" class="btn btn-default" type="button">Save</button> 93 <button id="cancel-change-image_install" type="button" class="btn btn-link">Cancel</button> 94 </form> 95 </dd> 96 {% endif %} 97 98 {% if package_classes_defined %} 99 <dt> 100 <span class="js-config-var-name js-config-var-managed-name">PACKAGE_CLASSES</span> 101 <span class="glyphicon glyphicon-question-sign get-help" title="Specifies the package manager to use when packaging data"></span> 102 </dt> 103 <dd class="variable-list"> 104 <span class="lead" id="package_classes">{{package_classes}}</span> 105 <span id="change-package_classes-icon" class="glyphicon glyphicon-edit"></span> 106 <form id="change-package_classes-form" style="display:none;"> 107 <div class="form-group"> 108 <label class="control-label"> 109 Root file system package format 110 <span class="glyphicon glyphicon-question-sign get-help" title="The package format used to generate the root file system. Options are <code>deb</code>, <code>ipk</code> and <code>rpm</code>"></i> 111 </label> 112 <select id="package_classes-select" class="form-control"> 113 <option>package_deb</option> 114 <option>package_ipk</option> 115 <option>package_rpm</option> 116 </select> 117 </div> 118 <div class="form-group"> 119 <label class="control-label"> 120 Additional package formats 121 <span class="glyphicon glyphicon-question-sign get-help" title="Extra package formats to build"></span> 122 </label> 123 <div class="checkbox"> 124 <label id="package_class_1"> 125 <input type="checkbox" id="package_class_1_input"> package_deb 126 </label> 127 </div> 128 <div class="checkbox"> 129 <label id="package_class_2"> 130 <input type="checkbox" id="package_class_2_input"> package_ipk 131 </label> 132 </div> 133 </div> 134 <button id="apply-change-package_classes" type="button" class="btn btn-default">Save</button> 135 <button id="cancel-change-package_classes" type="button" class="btn btn-link">Cancel</button> 136 </form> 137 </dd> 138 {% endif %} 139 140 {% if sstate_dir_defined %} 141 <dt> 142 <span class="js-config-var-name js-config-var-managed-name">SSTATE_DIR</span> 143 <span class="glyphicon glyphicon-question-sign get-help" title="Absolute path to the directory used to store shared state cache files. These files are reused across the builds, which makes the builds faster. By default, Toaster projects share the same cache directory"></span> 144 </dt> 145 <dd class="variable-list"> 146 <span id="sstate_dir" class="lead {% if not sstate_dir %} text-muted {% endif %}">{% if sstate_dir %}{{sstate_dir}}{%else%}Not set{%endif%}</span> 147 <span class="glyphicon glyphicon-edit" id="change-sstate_dir-icon"></span> 148 <form class="form-inline" id="change-sstate_dir-form" style="display:none;"> 149 <div class="form-group" id="validate-sstate_dir"> 150 <input type="text" class="form-control" id="new-sstate_dir" placeholder="Type an absolute path"> 151 </div> 152 <button id="apply-change-sstate_dir" class="btn btn-default" type="button">Save</button> 153 <button id="cancel-change-sstate_dir" type="button" class="btn btn-link">Cancel</button> 154 <p class="help-block" id="hintError-sstate_dir" style="display:none;">The directory path cannot include spaces or any of these characters: \ ? % * : | " " < ></p> 155 <p class="help-block" id="hintError-initialChar-sstate_dir" style="display:none;">The directory path should either start with a /, e.g. /home/toaster/sstate-cache; or with a variable, e.g. ${TOPDIR}/sstate-cache.</p> 156 </form> 157 </dd> 158 {% endif %} 159 </dl> 160 161 <!-- <ul class="list-unstyled configuration-list" id="configvar-list"> --> 162 <dl id="configvar-list"> 163 <!-- the added configuration variables are inserted here --> 164 </dl> 165 166 <!-- pass the fstypes list, black list, and externally managed variables here --> 167 {% for fstype in vars_fstypes %} 168 <input type="hidden" class="js-checkbox-fstypes-list" value="{{fstype}}"> 169 {% endfor %} 170 {% for b in vars_blacklist %} 171 <input type="hidden" class="js-config-blacklist-name" value="{{b}}"> 172 {% endfor %} 173 {% for b in vars_managed %} 174 <input type="hidden" class="js-config-managed-name" value="{{b}}"> 175 {% endfor %} 176 177 <form id="variable-form"> 178 <fieldset> 179 <legend>Add variable</legend> 180 <div class="row"> 181 <div class="col-md-3"> 182 <div id="add-configvar-name-div" class="form-group"> 183 <label class="control-label"> 184 Variable 185 <span class="glyphicon glyphicon-question-sign get-help" 186 title="Variable names are case sensitive, 187 cannot have spaces, and can only include letters, numbers, underscores 188 and dashes"></span> 189 </label> 190 <input type="text" class="form-control" placeholder="Type the variable name" id="variable"> 191 </div> 192 <p class="help-block" id="new-variable-error-message"></p> 193 <div class="form-group"> 194 <label clas="control-label">Value</label> 195 <input id="value" type="text" class="form-control" placeholder="Type the variable value"> 196 </div> 197 <button id="add-configvar-button" class="btn btn-default save" type="button" disabled>Add variable</button> 198 </div> 199 <div class="col-md-5 help-block"> 200 <h5>Some variables cannot be set from Toaster</h5> 201 <p>Toaster cannot set any variables that impact 1) the configuration of the build servers, 202 or 2) where artifacts produced by the build are stored. Such variables include: </p> 203 <p> 204 <code><a href="https://www.yoctoproject.org/docs/current/ref-manual/ref-manual.html#var-BB_DISKMON_DIRS" target="_blank">BB_DISKMON_DIRS</a></code> 205 <code><a href="https://www.yoctoproject.org/docs/current/ref-manual/ref-manual.html#var-BB_NUMBER_THREADS" target="_blank">BB_NUMBER_THREADS</a></code> 206 <code>CVS_PROXY_HOST</code> 207 <code>CVS_PROXY_PORT</code> 208 <code><a href="https://www.yoctoproject.org/docs/current/ref-manual/ref-manual.html#var-PARALLEL_MAKE" target="_blank">PARALLEL_MAKE</a></code> 209 <code><a href="https://www.yoctoproject.org/docs/current/ref-manual/ref-manual.html#var-TMPDIR" target="_blank">TMPDIR</a></code></p> 210 <p>Plus the following standard shell environment variables:</p> 211 <p><code>http_proxy</code> <code>ftp_proxy</code> <code>https_proxy</code> <code>all_proxy</code></p> 212 </div> 213 </div> 214 </fieldset> 215 </form> 216</div> 217 218</div> 219 220<script> 221 222// global variables 223var do_reload=false; 224 225// validate new variable name 226function validate_new_variable() { 227 var variable = $("input#variable").val(); 228 var value = $("input#value").val(); 229 230 // presumed innocence 231 $('#new-variable-error-message').text(""); 232 var error_msg = ""; 233 234 var existing_configvars = document.getElementsByClassName('js-config-var-name'); 235 for (var i = 0, length = existing_configvars.length; i < length; i++) { 236 if (existing_configvars[i].innerHTML.toUpperCase() == variable.toUpperCase()) { 237 error_msg = "This variable is already set in this page. Edit its value instead"; 238 } 239 } 240 241 var blacklist_configvars = document.getElementsByClassName('js-config-blacklist-name'); 242 for (var i = 0, length = blacklist_configvars.length; i < length; i++) { 243 if (blacklist_configvars[i].value.toUpperCase() == variable.toUpperCase()) { 244 error_msg = "You cannot edit this variable in Toaster because it is set by the build servers"; 245 } 246 } 247 248 var managed_configvars = document.getElementsByClassName('js-config-managed-name'); 249 for (var i = 0, length = managed_configvars.length; i < length; i++) { 250 if (managed_configvars[i].value.toUpperCase() == variable.toUpperCase()) { 251 error_msg = "You cannot set this variable here. Please set it in the <a href=\"{% url 'project' project.id %}\">project main page</a>"; 252 } 253 } 254 255 var bad_chars = /[^a-zA-Z0-9\-_/]/.test(variable); 256 var has_spaces = (0 <= variable.indexOf(" ")); 257 var only_spaces = (0 < variable.length) && (0 == variable.trim().length); 258 259 if (only_spaces) { 260 error_msg = "A valid variable name cannot include spaces"; 261 } else if (bad_chars && has_spaces) { 262 error_msg = "A valid variable name can only include letters, numbers and the special characters <code> _ - /</code>. Variable names cannot include spaces"; 263 } else if (bad_chars) { 264 error_msg = "A valid variable name can only include letters, numbers and the special characters <code>_ - /</code>"; 265 } 266 267 if ("" != error_msg) { 268 $('#new-variable-error-message').html(error_msg); 269 $(".save").attr("disabled","disabled"); 270 271 // add one (and only one) error class append 272 $("#add-configvar-name-div").addClass("has-error"); 273 $("#new-variable-error-message").addClass("text-danger"); 274 275 return false; 276 } else if (0 == variable.length) { 277 $(".save").attr("disabled","disabled"); 278 return false; 279 } 280 281 $("#add-configvar-name-div").removeClass("has-error"); 282 283 // now set the "Save" enablement if 'value' also passes 284 if (value.trim().length > 0) { 285 $(".save").removeAttr("disabled"); 286 } else { 287 $(".save").attr("disabled","disabled"); 288 } 289 290 return true; 291} 292 293// validate distro name 294function validate_distro_name() { 295 var value = $("input#new-distro").val(); 296 297 // presumed innocence 298 $('#distro-error-message').text(""); 299 var error_msg = ""; 300 301 var has_spaces = (0 <= value.indexOf(" ")); 302 303 if (has_spaces) { 304 error_msg = "A valid distro name cannot include spaces"; 305 } else if (0 == value.length) { 306 error_msg = " "; 307 } 308 309 if ("" != error_msg) { 310 $('#distro-error-message').text(error_msg); 311 $("#apply-change-distro").attr("disabled","disabled"); 312 313 // add one (and only one) error class append 314 $("#change-distro-form").addClass("has-error"); 315 316 return false; 317 } 318 319 $("#change-distro-form").removeClass("has-error"); 320 $("#apply-change-distro").removeAttr("disabled"); 321 return true; 322} 323 324// Test to insure at least one FS Type is checked 325function enableFsTypesSave() { 326 var any_checked = 0; 327 $(".fs-checkbox-fstypes:checked").each(function(){ 328 any_checked = 1; 329 }); 330 if ( 0 == any_checked ) { 331 $("#apply-change-image_fstypes").attr("disabled","disabled"); 332 $('.scrolling').addClass('has-error'); 333 $('#fstypes-error-message').show(); 334 } 335 else { 336 $("#apply-change-image_fstypes").removeAttr("disabled"); 337 $('.scrolling').removeClass('has-error'); 338 $('#fstypes-error-message').hide(); 339 } 340} 341 342// Preset or reset the Package Class checkbox labels 343function updatePackageClassCheckboxes() { 344 $('#package_class_1, #package_class_2').hide(); 345 if ($('select').val() == 'package_deb') { 346 $('#package_class_1').html('<input type="checkbox" id="package_class_1_input"> package_ipk'); 347 $('#package_class_2').html('<input type="checkbox" id="package_class_2_input"> package_rpm'); 348 } 349 if ($('select').val() == 'package_ipk') { 350 $('#package_class_1').html('<input type="checkbox" id="package_class_1_input"> package_deb'); 351 $('#package_class_2').html('<input type="checkbox" id="package_class_2_input"> package_rpm'); 352 } 353 if ($('select').val() == 'package_rpm') { 354 $('#package_class_1').html('<input type="checkbox" id="package_class_1_input"> package_deb'); 355 $('#package_class_2').html('<input type="checkbox" id="package_class_2_input"> package_ipk'); 356 } 357 $('#package_class_1, #package_class_2').fadeIn(1500); 358} 359 360// Re-assert handlers when the page is served and/or refreshed via Ajax 361function setEventHandlersForDynamicElements() { 362 363 // change variable value 364 $('.js-icon-pencil-config_var').click(function (evt) { 365 var pk = $(this).attr("x-data"); 366 var current_val = $("#config_var_value_"+pk).text(); 367 $("#config_var_value_"+pk).hide(); 368 $("#config_var_trash_"+pk).hide(); 369 $(".js-icon-pencil-config_var[x-data="+pk+"]").hide(); 370 $("#change-config_var-form_"+pk).slideDown(); 371 $("#new-config_var_"+pk).val(current_val); 372 if ( $("#new-config_var_"+pk).val().length ) { 373 $("#apply-change-config_var_"+pk).removeAttr("disabled"); 374 } 375 else { 376 $("#apply-change-config_var_"+pk).attr("disabled"); 377 } 378 }); 379 380 $('.js-cancel-change-config_var').click(function (evt) { 381 var pk = evt.target.attributes["x-data"].value; 382 $("#change-config_var-form_"+pk).slideUp(function() { 383 $("#config_var_trash_"+pk).show(); 384 $('#config_var_value_'+pk).show(); 385 $(".js-icon-pencil-config_var[x-data="+pk+"]").show(); 386 }); 387 }); 388 389 $(".js-new-config_var").on('input', function(){ 390 if ($(this).val().length == 0) { 391 $(this).parent("div").next(".btn-default").attr("disabled","disabled"); 392 } 393 else { 394 $(this).parent("div").next(".btn-default").removeAttr("disabled"); 395 } 396 }); 397 398 $('.js-apply-change-config_var').click(function (evt) { 399 var xdata = evt.target.attributes["x-data"].value.split(":"); 400 var pk = xdata[0]; 401 var variable = xdata[1]; 402 var val = $('#new-config_var_'+pk).val(); 403 postEditAjaxRequest({"configvarChange" : variable+':'+val}); 404 $("#change-config_var-form_"+pk).slideUp(); 405 $("#config_var_trash_"+pk).fadeIn(); 406 $('#config_var_value_'+pk).fadeIn(); 407 $(".js-icon-pencil-config_var[x-data="+pk+"]").fadeIn(); 408 }); 409 410 // delete variable 411 $(".js-icon-trash-config_var").click(function (evt) { 412 var pk = $(this).attr("x-data"); 413 414 // fade out the variable+value div, then refresh the variable list 415 $(this).fadeOut(); 416 $(this).tooltip("hide"); 417 $("config_var_entry_"+pk).fadeOut(); 418 $('#config_var_value_'+pk).parent("dd").fadeOut(); 419 postEditAjaxRequest({"configvarDel": evt.target.attributes["x-data"].value}); 420 }); 421 422} 423 424function onEditPageUpdate(data) { 425 // update targets 426 var i; var orightml = ""; 427 428 var configvars_sorted = data.configvars.sort(function(a, b){return a[0] > b[0]}); 429 430 var managed_configvars = document.getElementsByClassName('js-config-var-managed-name'); 431 432 for (i = 0; i < configvars_sorted.length; i++) { 433 // skip if the variable name has a special context (not user defined) 434 var var_context=undefined; 435 for (var j = 0, length = managed_configvars.length; j < length; j++) { 436 if ((managed_configvars[j].innerHTML == configvars_sorted[i][0]) || 437 (managed_configvars[j].value == configvars_sorted[i][0]) ) { 438 var_context='m'; 439 } 440 } 441 if (configvars_sorted[i][0].startsWith("INTERNAL_")) { 442 var_context='m'; 443 } 444 if (var_context == undefined) { 445 orightml += '<dt><span id="config_var_entry_'+configvars_sorted[i][2]+'" class="js-config-var-name"></span><span class="glyphicon glyphicon-trash js-icon-trash-config_var" id="config_var_trash_'+configvars_sorted[i][2]+'" x-data="'+configvars_sorted[i][2]+'"></span> </dt>' 446 orightml += '<dd class="variable-list">' 447 orightml += ' <span class="lead" id="config_var_value_'+configvars_sorted[i][2]+'"></span>' 448 orightml += ' <span class="glyphicon glyphicon-edit js-icon-pencil-config_var" x-data="'+configvars_sorted[i][2]+'"></span>' 449 orightml += ' <form class="form-inline" id="change-config_var-form_'+configvars_sorted[i][2]+'" style="display:none;">' 450 orightml += ' <div class="form-group">' 451 orightml += ' <input type="text" class="form-control js-new-config_var" id="new-config_var_'+configvars_sorted[i][2]+'" value=""></div>' 452 orightml += ' <button id="apply-change-config_var_'+configvars_sorted[i][2]+'" class="btn btn-default js-apply-change-config_var" type="button" x-data="'+configvars_sorted[i][2]+':'+configvars_sorted[i][0]+'" disabled>Save</button>' 453 orightml += ' <button type="button" class="btn btn-link js-cancel-change-config_var" x-data="'+configvars_sorted[i][2]+'">Cancel</button>' 454 orightml += ' </form>' 455 orightml += '</dd>' 456 } 457 } 458 459 // update configvars list HTML framework 460 $("dl#configvar-list").html(orightml); 461 462 // insert the name/value pairs safely as non-HTML 463 for (i = 0; i < configvars_sorted.length; i++) { 464 $('#config_var_entry_'+configvars_sorted[i][2]).text(configvars_sorted[i][0]); 465 $('#config_var_value_'+configvars_sorted[i][2]).text(configvars_sorted[i][1]); 466 } 467 468 // Add the tooltips 469 $(".js-icon-trash-config_var").each( function(){ setDeleteTooltip($(this)); }); 470 $(".js-icon-pencil-config_var").each(function(){ setChangeTooltip($(this)); }); 471 472 // re-assert these event handlers 473 setEventHandlersForDynamicElements(); 474} 475 476function onEditAjaxSuccess(data, textstatus) { 477 console.log("XHR returned:", data, "(" + textstatus + ")"); 478 if (data.error != "ok") { 479 alert("error on request:\n" + data.error); 480 return; 481 } 482 483 // delayed page reload? 484 if (do_reload) { 485 do_reload=false; 486 location.reload(true); 487 } else { 488 onEditPageUpdate(data); 489 } 490} 491 492function onEditAjaxError(jqXHR, textstatus, error) { 493 alert("XHR errored:\n" + error + "\n(" + textstatus + ")"); 494 // re-assert the event handlers 495} 496 497/* ensure cookie exists {% csrf_token %} */ 498function postEditAjaxRequest(reqdata) { 499 var ajax = $.ajax({ 500 type:"POST", 501 data: $.param(reqdata), 502 url:"{% url 'xhr_configvaredit' project.id%}", 503 headers: { 'X-CSRFToken': $.cookie("csrftoken")}, 504 success: onEditAjaxSuccess, 505 error: onEditAjaxError, 506 }) 507} 508 509function setDeleteTooltip(object) { 510 object.tooltip({ container: 'body', html: true, delay: {show: 400}, title: "Delete" }); 511} 512function setChangeTooltip(object) { 513 object.tooltip({ container: 'body', html: true, delay: {show: 400}, title: "Change" }); 514} 515 516$(document).ready(function() { 517 518 // 519 // Register handlers for static elements 520 // 521 522 {% if distro_defined %} 523 // change distro variable 524 $('#change-distro-icon').click(function() { 525 $('#change-distro-icon, #distro').hide(); 526 $("#change-distro-form").slideDown(); 527 $("#new-distro").val( $('#distro').text() ); 528 $("#apply-change-distro").removeAttr("disabled"); 529 }); 530 531 $('#cancel-change-distro').click(function(){ 532 $("#change-distro-form").slideUp(function() { 533 $('#distro, #change-distro-icon').show(); 534 535 // reset any dangling error state 536 $('#distro-error-message').text(""); 537 $("#change-distro-form").removeClass("has-error"); 538 }); 539 }); 540 541 // validate new distro name 542 $("input#new-distro").on('input', function (evt) { 543 validate_distro_name(); 544 }); 545 546 $('#apply-change-distro').click(function(){ 547 //$('#repo').parent().removeClass('highlight-go'); 548 var name = $('#new-distro').val(); 549 postEditAjaxRequest({"configvarChange" : 'DISTRO:'+name}); 550 $('#distro').text(name); 551 $("#change-distro-form").slideUp(function () { 552 $('#distro, #change-distro-icon').show(); 553 }); 554 }); 555 {% endif %} 556 557 {% if dl_dir_defined %} 558 559 // change DL_DIR variable 560 $('#change-dl_dir-icon').click(function() { 561 $('#change-dl_dir-form').removeClass('has-error'); 562 // preset the edit value 563 var current_val = $("#dl_dir").text().trim(); 564 if (current_val == "Not set") { 565 current_val=""; 566 $("#apply-change-dl_dir").attr("disabled","disabled"); 567 } 568 $("input#new-dl_dir").val(current_val); 569 // enable / disable the save button based on the input value 570 if ( current_val.length ) { 571 $("#apply-change-dl_dir").removeAttr("disabled"); 572 } 573 else { 574 $("#apply-change-dl_dir").attr("disabled","disabled"); 575 } 576 577 $('#change-dl_dir-icon, #dl_dir').hide(); 578 $("#change-dl_dir-form").slideDown(); 579 }); 580 581 $('#cancel-change-dl_dir').click(function(){ 582 $("#hintError-dl_dir").hide(); 583 $("#hintError-initialChar-dl_dir").hide(); 584 $("#change-dl_dir-form").slideUp(function() { 585 $('#dl_dir, #change-dl_dir-icon').show(); 586 }); 587 }); 588 589 $("#new-dl_dir").on('input', function(){ 590 if ($(this).val().trim().length == 0) { 591 $("#apply-change-dl_dir").attr("disabled","disabled"); 592 $('#change-dl_dir-form').addClass('has-error'); 593 $('#hintError-dl_dir').hide(); 594 $('#hintError-initialChar-dl_dir').hide(); 595 } 596 else { 597 var input = $(this); 598 var reBeginWithSlash = /^\//; 599 var reCheckVariable = /^\$/; 600 var re = /([ <>\\|":%\?\*]+)/; 601 var invalidDir = re.test(input.val()); 602 var invalidSlash = reBeginWithSlash.test(input.val()); 603 var invalidVar = reCheckVariable.test(input.val()); 604 if (!invalidSlash && !invalidVar) { 605 $('#change-dl_dir-form').addClass('has-error'); 606 $("#apply-change-dl_dir").attr("disabled","disabled"); 607 $('#hintError-initialChar-dl_dir').show(); 608 } else if (invalidDir) { 609 $('#change-dl_dir-form').addClass('has-error'); 610 $("#apply-change-dl_dir").attr("disabled","disabled"); 611 $('#hintError-dl_dir').show(); 612 } else { 613 $('#change-dl_dir-form').removeClass('has-error'); 614 $("#apply-change-dl_dir").removeAttr("disabled"); 615 $('#hintError-dl_dir').hide(); 616 $('#hintError-initialChar-dl_dir').hide(); 617 } 618 } 619 }); 620 621 $('#apply-change-dl_dir').click(function(){ 622 var value = $('#new-dl_dir').val().trim(); 623 postEditAjaxRequest({"configvarChange" : 'DL_DIR:'+value}); 624 $('#dl_dir').text(value); 625 $('#dl_dir').removeClass('muted'); 626 $("#change-dl_dir-form").slideUp(function () { 627 $('#dl_dir, #change-dl_dir-icon').show(); 628 }); 629 }); 630 631 {% endif %} 632 633 {% if fstypes_defined %} 634 // change IMAGE_FSTYPES variable 635 636 // get value of fstypes and add to the textbox 637 $("#new-imagefs_types").val("{{fstypes}}"); 638 639 // If value of new-imagefs_types is empty disable save button 640 $("#new-imagefs_types").on("input", function() { 641 $(this).val($(this).val().replace(/\s+/g,' ')); 642 if ($(this).val().length === 0) { 643 //$('#apply-change-image_fstypes').prop('disabled', true); 644 $('#apply-change-image_fstypes').attr("disabled", "disabled"); 645 } else { 646 //$('#apply-change-image_fstypes').prop('disabled', false); 647 $('#apply-change-image_fstypes').removeAttr("disabled"); 648 } 649 650 /*If user types imagefs do the action on checkboxes. 651 Lets say if an imagefstype typed by user and the same 652 imagefs is unchecked in the checkbox, then checkbox needs 653 to get checked. Similarly when user deletes imagefs from 654 textbox the checkbox which is checked gets unchecked. 655 */ 656 $('#all-image_fstypes input').each(function(){ 657 var imagefs_userval = $('#new-imagefs_types').val(); 658 if( imagefs_userval.indexOf($(this).val()) > -1) { 659 $(this).prop('checked', true); 660 } else { 661 $(this).prop('checked', false); 662 } 663 }); 664 665 // Validate underscore in image fs types 666 if ($(this).val().indexOf('_') > -1) { 667 $('#validate-image_fstypes').addClass('has-error'); 668 $('#hintError-image-fs_type').show(); 669 $("#apply-change-image_fstypes").prop("disabled", true); 670 } else { 671 $('#validate-image_fstypes').removeClass('has-error'); 672 $('#hintError-image-fs_type').hide(); 673 } 674 }); 675 676 $('#change-image_fstypes-icon').click(function() { 677 $('#change-image_fstypes-icon, #image_fstypes').hide(); 678 $("#change-image_fstypes-form").slideDown(); 679 // avoid false substring matches by including space separators 680 var html = ""; 681 var fstypes = " " + document.getElementById("image_fstypes").innerHTML + " "; 682 var fstypes_list = document.getElementsByClassName('js-checkbox-fstypes-list'); 683 // Add the checked boxes first 684 if (" " != fstypes) { 685 for (var i = 0, length = fstypes_list.length; i < length; i++) { 686 if (0 <= fstypes.indexOf(" "+fstypes_list[i].value+" ")) { 687 html += '<div class="checkbox"><label><input type="checkbox" class="fs-checkbox-fstypes" value="'+fstypes_list[i].value+'" checked="checked">'+fstypes_list[i].value+'</label></div>'; 688 } 689 } 690 } 691 // Add the un-checked boxes second 692 for (var i = 0, length = fstypes_list.length; i < length; i++) { 693 if (0 > fstypes.indexOf(" "+fstypes_list[i].value+" ")) { 694 html += '<div class="checkbox"><label><input type="checkbox" class="fs-checkbox-fstypes" value="'+fstypes_list[i].value+'">'+fstypes_list[i].value+'</label></div>'; 695 } 696 } 697 // Add the 'no search matches' line last 698 html += '<label id="no-match-fstypes" class="text-muted">No image types found</label>\n'; 699 // Display the list 700 document.getElementById("all-image_fstypes").innerHTML = html; 701 $('#no-match-fstypes').hide(); 702 703 // clear the previous filter values and warning messages 704 $("input#filter-image_fstypes").val(""); 705 }); 706 707 // When checkbox is checked/unchecked kindly update the text 708 $(document).on("change", "#all-image_fstypes :checkbox", function() { 709 var imagefs = $(this); 710 var imagefs_obj = $('#new-imagefs_types'); 711 var imagefs_userval = imagefs_obj.val(); 712 if ($(this).is(':checked')) { 713 if (imagefs_userval.indexOf($(imagefs).val()) === -1) { 714 imagefs_obj.val(imagefs_userval + " " + $(imagefs).val()); 715 } 716 } else { 717 if (imagefs_userval.indexOf($(imagefs).val()) > -1) { 718 imagefs_obj.val(imagefs_userval.replace($(imagefs).val(), '').trim()); 719 } 720 } 721 if ($('#new-imagefs_types').val().length === 0) { 722 $("#apply-change-image_fstypes").prop("disabled", true); 723 $('#fstypes-error-message').show(); 724 } else { 725 $("#apply-change-image_fstypes").prop("disabled", false); 726 $('#fstypes-error-message').hide(); 727 } 728 }); 729 730 $('#cancel-change-image_fstypes').click(function(){ 731 $("#new-imagefs_types").val("{{fstypes}}"); 732 $("#change-image_fstypes-form").slideUp(function() { 733 $('#image_fstypes, #change-image_fstypes-icon').show(); 734 }); 735 }); 736 737 $('#filter-image_fstypes').on('input', function(){ 738 var valThis = $(this).val().toLowerCase(); 739 var matchCount=0; 740 $('#all-image_fstypes label').each(function(){ 741 var text = $(this).text().toLowerCase(); 742 var match = text.indexOf(valThis); 743 if (match >= 0) { 744 $(this).show(); 745 matchCount += 1; 746 } 747 else { 748 $(this).hide(); 749 } 750 }); 751 if (matchCount === 0) { 752 $('#no-match-fstypes').show(); 753 } else { 754 $('#no-match-fstypes').hide(); 755 } 756 }); 757 758 $('#apply-change-image_fstypes').click(function(){ 759 var fstypes = $('#new-imagefs_types').val(); 760 761 postEditAjaxRequest({"configvarChange" : 'IMAGE_FSTYPES:'+fstypes}); 762 $('#image_fstypes').text(fstypes); 763 $('#image_fstypes').parent().removeClass('muted'); 764 765 $("#change-image_fstypes-form").slideUp(function() { 766 $('#image_fstypes, #change-image_fstypes-icon').show(); 767 }); 768 }); 769 {% endif %} 770 771 772 {% if image_install_append_defined %} 773 774 // init IMAGE_INSTALL_append trash icon 775 setDeleteTooltip($('#delete-image_install-icon')); 776 777 // change IMAGE_INSTALL_append variable 778 $('#change-image_install-icon').click(function() { 779 // preset the edit value 780 var current_val = $("span#image_install").text().trim(); 781 if (current_val == "Not set") { 782 current_val=""; 783 $("#apply-change-image_install").attr("disabled","disabled"); 784 } else { 785 // insure these non-empty values have single space prefix 786 current_val=" " + current_val; 787 $("#apply-change-image_install").removeAttr("disabled"); 788 } 789 $("input#new-image_install").val(current_val); 790 791 $('#change-image_install-icon, #delete-image_install-icon, #image_install').hide(); 792 $("#change-image_install-form").slideDown(); 793 }); 794 795 $('#cancel-change-image_install').click(function(){ 796 $("#change-image_install-form").slideUp(function() { 797 $('#image_install, #change-image_install-icon').show(); 798 if ($("span#image_install").text() != "Not set") { 799 $('#delete-image_install-icon').show(); 800 setDeleteTooltip($('#delete-image_install-icon')); 801 } 802 }); 803 }); 804 805 $("#new-image_install").on('input', function(){ 806 if ($(this).val().trim().length == 0) { 807 $("#apply-change-image_install").attr("disabled","disabled"); 808 } 809 else { 810 $("#apply-change-image_install").removeAttr("disabled"); 811 } 812 }); 813 814 $('#apply-change-image_install').click(function(){ 815 // insure these non-empty values have single space prefix 816 var value = " " + $('#new-image_install').val().trim(); 817 postEditAjaxRequest({"configvarChange" : 'IMAGE_INSTALL_append:'+value}); 818 $('#image_install').text(value); 819 $('#image_install').removeClass('text-muted'); 820 $("#change-image_install-form").slideUp(function () { 821 $('#image_install, #change-image_install-icon').show(); 822 if (value.length > -1) { 823 $('#delete-image_install-icon').show(); 824 setDeleteTooltip($('#delete-image_install-icon')); 825 } 826 }); 827 }); 828 829 // delete IMAGE_INSTALL_append variable value 830 $('#delete-image_install-icon').click(function(){ 831 $(this).tooltip('hide'); 832 postEditAjaxRequest({"configvarChange" : 'IMAGE_INSTALL_append:'+''}); 833 $('#image_install').parent().fadeOut(1000, function(){ 834 $('#image_install').addClass('text-muted'); 835 $('#image_install').text('Not set'); 836 $('#delete-image_install-icon').hide(); 837 $('#image_install').parent().fadeIn(1000); 838 }); 839 }); 840 {% endif %} 841 842 843 {% if package_classes_defined %} 844 // change PACKAGE_CLASSES variable 845 $('#change-package_classes-icon').click(function() { 846 $('#change-package_classes-icon, #package_classes').hide(); 847 $("#change-package_classes-form").slideDown(); 848 849 // initialize the pulldown and checkboxes 850 var value = $("#package_classes").text(); 851 if ( value.indexOf("package_deb") == 0 ) { 852 $("#package_classes-select").prop('selectedIndex', 0); 853 updatePackageClassCheckboxes(); 854 if ( value.indexOf("_ipk") > 0 ) { 855 $("#package_class_1_input").attr("checked",true); 856 } 857 if ( value.indexOf("_rpm") > 0 ) { 858 $("#package_class_2_input").attr("checked",true); 859 } 860 } 861 862 if ( value.indexOf("package_ipk") == 0 ) { 863 $("#package_classes-select").prop('selectedIndex', 1); 864 updatePackageClassCheckboxes(); 865 if ( value.indexOf("_deb") > 0 ) { 866 $("#package_class_1_input").attr("checked",true); 867 } 868 if ( value.indexOf("_rpm") > 0 ) { 869 $("#package_class_2_input").attr("checked",true); 870 } 871 } 872 873 if ( value.indexOf("package_rpm") == 0 ) { 874 $("#package_classes-select").prop('selectedIndex', 2); 875 updatePackageClassCheckboxes(); 876 if ( value.indexOf("_deb") > 0 ) { 877 $("#package_class_1_input").attr("checked",true); 878 } 879 if ( value.indexOf("_ipk") > 0 ) { 880 $("#package_class_2_input").attr("checked",true); 881 } 882 } 883 }); 884 885 $('#cancel-change-package_classes').click(function(){ 886 $("#change-package_classes-form").slideUp(function() { 887 $('#package_classes, #change-package_classes-icon').show(); 888 }); 889 }); 890 891 $('select').change(function() { 892 updatePackageClassCheckboxes(); 893 }); 894 895 $('#apply-change-package_classes').click(function(){ 896 var e = document.getElementById("package_classes-select"); 897 var val = e.options[e.selectedIndex].text; 898 899 pc1_checked = document.getElementById("package_class_1_input").checked; 900 pc2_checked = document.getElementById("package_class_2_input").checked; 901 if (val == "package_deb") { 902 if (pc1_checked) val = val + " package_ipk"; 903 if (pc2_checked) val = val + " package_rpm"; 904 } 905 if (val == "package_ipk") { 906 if (pc1_checked) val = val + " package_deb"; 907 if (pc2_checked) val = val + " package_rpm"; 908 } 909 if (val == "package_rpm") { 910 if (pc1_checked) val = val + " package_deb"; 911 if (pc2_checked) val = val + " package_ipk"; 912 } 913 914 $('#package_classes').text(val); 915 //$('#package_classes').parent().removeClass('muted'); 916 postEditAjaxRequest({"configvarChange" : 'PACKAGE_CLASSES:'+val}); 917 $("#change-package_classes-form").slideUp(function() { 918 $('#package_classes, #change-package_classes-icon').show(); 919 }); 920 }); 921 {% endif %} 922 923 {% if sstate_dir_defined %} 924 925 // change SSTATE_DIR variable 926 $('#change-sstate_dir-icon').click(function() { 927 $('#change-sstate_dir-form').removeClass('has-error'); 928 // preset the edit value 929 var current_val = $("span#sstate_dir").text().trim(); 930 if (current_val == "Not set") { 931 current_val=""; 932 $("#apply-change-sstate_dir").attr("disabled","disabled"); 933 } 934 $("input#new-sstate_dir").val(current_val); 935 936 // enable / disable the save button based on the input value 937 if ( current_val.length ) { 938 $("#apply-change-sstate_dir").removeAttr("disabled"); 939 } 940 else { 941 $("#apply-change-sstate_dir").attr("disabled","disabled"); 942 } 943 944 $('#change-sstate_dir-icon, #sstate_dir').hide(); 945 $("#change-sstate_dir-form").slideDown(); 946 }); 947 948 $('#cancel-change-sstate_dir').click(function(){ 949 $("#hintError-sstate_dir").hide(); 950 $("#hintError-initialChar-sstate_dir").hide(); 951 $("#change-sstate_dir-form").slideUp(function() { 952 $('#sstate_dir, #change-sstate_dir-icon').show(); 953 }); 954 }); 955 956 $("#new-sstate_dir").on('input', function(){ 957 if ($(this).val().trim().length == 0) { 958 $("#apply-change-sstate_dir").attr("disabled","disabled"); 959 $('#change-sstate_dir-form').addClass('has-error'); 960 $('#hintError-sstate_dir').hide(); 961 $('#hintError-initialChar-sstate_dir').hide(); 962 } 963 else { 964 var input = $(this); 965 var reBeginWithSlash = /^\//; 966 var reCheckVariable = /^\$/; 967 var re = /([ <>\\|":%\?\*]+)/; 968 var invalidDir = re.test(input.val()); 969 var invalidSlash = reBeginWithSlash.test(input.val()); 970 var invalidVar = reCheckVariable.test(input.val()); 971 if (!invalidSlash && !invalidVar) { 972 $('#change-sstate_dir-form').addClass('has-error'); 973 $("#apply-change-sstate_dir").attr("disabled","disabled"); 974 $('#hintError-initialChar-sstate_dir').show(); 975 } else if (invalidDir) { 976 $('#change-sstate_dir-form').addClass('has-error'); 977 $("#apply-change-sstate_dir").attr("disabled","disabled"); 978 $('#hintError-sstate_dir').show(); 979 } else { 980 $('#change-sstate_dir-form').removeClass('has-error'); 981 $("#apply-change-sstate_dir").removeAttr("disabled"); 982 $('#hintError-sstate_dir').hide(); 983 $('#hintError-initialChar-sstate_dir').hide(); 984 } 985 } 986 }); 987 988 $('#apply-change-sstate_dir').click(function(){ 989 var value = $('#new-sstate_dir').val().trim(); 990 postEditAjaxRequest({"configvarChange" : 'SSTATE_DIR:'+value}); 991 $('#sstate_dir').text(value); 992 $('#sstate_dir').removeClass('text-muted'); 993 $("#change-sstate_dir-form").slideUp(function () { 994 $('#sstate_dir, #change-sstate_dir-icon').show(); 995 }); 996 }); 997 998 {% endif %} 999 1000 // add new variable 1001 $("button#add-configvar-button").click( function (evt) { 1002 var variable = $("input#variable").val(); 1003 var value = $("input#value").val(); 1004 1005 postEditAjaxRequest({"configvarAdd" : variable+':'+value}); 1006 1007 // clear the previous values 1008 $("input#variable").val(""); 1009 $("input#value").val(""); 1010 // Disable add button 1011 $(".save").attr("disabled","disabled"); 1012 1013 // Reload page if admin-removed core managed value is manually added back in 1014 if (0 <= " DISTRO DL_DIR IMAGE_FSTYPES IMAGE_INSTALL_append PACKAGE_CLASSES SSTATE_DIR ".indexOf( " "+variable+" " )) { 1015 // delayed reload to avoid race condition with postEditAjaxRequest 1016 do_reload=true; 1017 } 1018 }); 1019 1020 // validate new variable name and value 1021 $("#variable, #value").on('input', function() { 1022 validate_new_variable(); 1023 }); 1024 1025 // 1026 // draw and register the dynamic configuration variables and handlers 1027 // 1028 1029 var data = { 1030 configvars : [] 1031 }; 1032 {% for c in configvars %} 1033 data.configvars.push([ "{{c.name}}","{{c.value}}","{{c.pk}}" ]); 1034 {% if '' != vars_context|get_dict_value:c.name %} 1035 data.vars_context[ "{{c.name}}" ] = "{{vars_context|get_dict_value:c.name }}"; 1036 {% endif %} 1037 {% endfor %} 1038 1039 // draw these elements and assert their event handlers 1040 onEditPageUpdate(data); 1041}); 1042 1043</script> 1044 1045{% endblock %} 1046